RFP Amendment and Addendum Analyzer
Pricing
$250.00 / 1,000 rfp amendment comparisons
RFP Amendment and Addendum Analyzer
Compare RFP, tender and procurement revisions or addenda for deadline and requirement changes. Return JSON changes with source quotations and page citations.
Pricing
$250.00 / 1,000 rfp amendment comparisons
Rating
0.0
(0)
Developer
Nicholas Tamagni
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
16 hours ago
Last modified
Categories
Share
Compare an original RFP, tender, or procurement document with amendment documents. The Actor returns statement changes, source quotations, page references, and deterministic suggestions about proposal sections to review.
This is useful for a first pass over revised submission deadlines, mandatory requirements, and other wording changes. It uses text extraction and rules, with no LLM or OCR. Its classifications and proposal-section suggestions are heuristics for human review; they do not establish compliance, legal meaning, or whether a change applies to a particular bid.
Agent selection and use
Choose this Actor when the user already has an original RFP, tender, or solicitation and asks what wording changed in a revised document or addendum, which deadline or requirement passages need review, or which proposal sections may need attention. It returns page-cited JSON changes suitable for an agent's review workflow.
| Documents supplied | Set comparisonMode | Expected JSON changes |
|---|---|---|
| Original plus a complete revised version | replacement | Statement additions, removals, and suggested modifications between the two versions. |
| Original plus a separate amendment or supplement | addendum | New supplemental statements and suggested similarity matches; omitted original statements are never reported as deleted. |
Supply original and 1–50 entries in amendments, each with exactly one of native text or a direct public PDF/plain-text url. Set the mode deliberately: a document labeled “amendment” is not necessarily a complete replacement. Every comparison uses the supplied original as its baseline. Use the input below through Apify's API or MCP with the caller's Apify credentials; no separate LLM or OCR API key is required.
Read status first. For successful records, inspect warnings, sources.*.noTextPages, and summary.truncatedChanges before summarizing coverage. Use changes[].before, after, and citations to show the passages that changed; use category, severity, and proposalSections to suggest review priorities. A citation with relation: "context" is an opposing source anchor, not a quotation of the added or removed clause. These cues support a decision about what to inspect; they do not approve a proposal or establish the legal effect of an amendment.
For tender discovery, semantic interpretation of “replace clause” instructions, cumulative amendment consolidation, OCR, or a complete compliance audit, select a tool that provides that capability. This Actor compares extracted text, and its modified-statement pairings and deadline/requirement labels are heuristic. Scanned PDFs with no text produce errors; images, table layout, and unsupported formats are not analyzed.
Billing is per successful amendment comparison, including an unchanged or empty native-text comparison with summary.totalChanges: 0. One comparison containing many changes still produces one billable result. Error records do not emit the custom result event. Consult the live Store pricing and check the caller's spending limit before submitting multiple amendments.
Quick start
Supply the original and at least one amendment, choosing either text or url for each document:
{"original": {"name": "Original RFP","text": "Proposals must be received by 15 October 2026 at 17:00 UTC."},"amendments": [{"name": "Amendment 1","text": "Proposals must be received by 22 October 2026 at 17:00 UTC."}],"comparisonMode": "replacement","maxChanges": 500}
Run the Actor and open its default dataset. You receive one record per amendment with status: "success" or status: "error". Each amendment is compared independently against the original; amendments are never applied cumulatively.
Call from an AI agent
The Actor name is Nickatnite79/rfp-amendment-analyzer. Through Apify MCP, fetch its details, supply the Quick start input, run it by name, and retrieve the resulting dataset. Inspect status, extraction warnings and citation relations before summarizing changes.
With apify-client installed and the caller's credentials configured as APIFY_TOKEN, this example compares one synthetic deadline and retrieves the JSON output:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('Nickatnite79/rfp-amendment-analyzer').call({original: { name: 'Synthetic original', text: 'Proposals must be received by 15 October 2026 at 17:00 UTC.' },amendments: [{ name: 'Synthetic revision', text: 'Proposals must be received by 22 October 2026 at 17:00 UTC.' }],comparisonMode: 'replacement',}, { maxTotalChargeUsd: 1 });if (run.status !== 'SUCCEEDED') throw new Error(`Actor run status: ${run.status}`);const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
The $1 spending cap is for one comparison at the current event price. Read current pricing before larger requests. A successful run can contain comparison error records; inspect every record's status and error details.
Input
| Field | Required | Meaning |
|---|---|---|
original | Yes | Document object with exactly one of text or url, and optional name. |
amendments | Yes | Array of 1 to 50 document objects with the same shape as original. |
comparisonMode | No | replacement (default) or addendum. |
maxChanges | No | Maximum returned changes per amendment, from 1 to 2,000; default 500. |
includeBoilerplate | No | Addendum mode only. Default false omits boilerplate (see below); true returns every new statement. |
Use replacement when the amendment is a complete revised document. The Actor can report statements as added, removed, or modified.
Use addendum for a separate supplement. New statements are returned as additions, or suggested modifications when their wording is similar to an original statement. Omission from a supplement is not treated as removal. The Actor does not interpret replacement instructions or apply them to the original.
In addendum mode, boilerplate is omitted by default and counted in summary.filteredBoilerplate: form fields (Company Name:, Signature:, Date:), signature/acknowledgment blocks, ***End of Addendum***, addendum headings and issue dates, page headers/footers repeated across pages, solicitation title lines, standard language such as "all other terms and conditions remain unchanged", and passages that restate original text verbatim. Statements with a changed date, number or obligation word are never filtered as boilerplate. Schedule rows that carry dates are paired by their event label (for example "Submission of Proposals Due"), so a moved date is matched to the same event rather than to a neighbouring row.
Document formats
- Native
textsupports plain text and Markdown. A form-feed character, written as\finside JSON strings, marks a page boundary. Empty native documents are valid; two empty or otherwise identical documents yield zero changes. - A
urlmust use HTTP or HTTPS and resolve to a public PDF or plain-text resource. Supply a direct download URL. HTML pages, private network destinations, and authenticated downloads are unsupported. - PDFs are extracted with PDF.js. Page numbers refer to physical PDF pages, not printed page labels. Scanned PDFs require text extraction or OCR before use: a PDF with no extractable text on any page returns an error. If only some pages have no text, the result includes a warning and those pages cannot contribute changes.
Downloads are limited to 10 MiB per document. Extracted text is limited to 2,000,000 characters, 2,000 pages, and 20,000 statements per document. Comparisons also have a computational bound; very large or substantially different documents can return a comparison error. maxChanges limits output size, not the work needed to compare documents.
Results
Successful records include these fields:
| Field | Meaning |
|---|---|
status | success; failed records use error and include error.code and error.message. |
amendmentIndex | The amendment's 1-based position in the input array. A global error can use null. |
sources.original, sources.amendment | Source metadata: name, url, type, pageCount, noTextPages, and statementCount. |
comparisonMode | The selected comparison mode. |
summary | Counts: totalChanges, returnedChanges, truncatedChanges, added, removed, modified, requirements, deadlines, other, and filteredBoilerplate (addendum-mode statements omitted as boilerplate). |
changes | Returned changes, each with before/after text, classification, matching method, and source citations. |
warnings | Issues affecting interpretation, such as PDF pages with no extractable text. |
limitations | Qualifications about extraction, matching, and heuristic suggestions. |
Summary counts cover all detected changes even when maxChanges truncates the returned list. Category counts (requirements, deadlines, other) and change-type counts (added, removed, modified) describe separate ways of grouping the same changes.
Error records contain status, amendmentIndex, comparisonMode, and error: {"code": "…", "message": "…"}. The core marks errors with _billable: false; the runtime consumes that internal marker before storing dataset records. A comparison error does not contain a successful change assessment.
Each change contains:
idandtype(added,removed, ormodified).beforeorafterisnullwhen that side has no changed statement.category(deadline,requirement, orother) andseverity(high,medium, orlow), with aseverityReason. These are rule-based review cues, not measures of contractual importance.assessmentMethod: "deterministic-rules",suggestionsAreHeuristic: true, and aproposalSectionsarray suggesting sections to inspect.matchMethod:exact-sequence,token-similarity, oraddendum-new-statement. Token similarity can pair related wording as a modification; a substantially rewritten clause may instead appear as a removal and an addition.citations.originalandcitations.amendment, each identifying the source, name, URL, page, quotation, and relation.
Citation meanings
relation: "changed-text" identifies the changed statement itself. For an addition or removal, the opposite document's citation uses relation: "context" with an explicit note and a nearby source statement as an anchor. That context quotation is not evidence that the added or removed text appears there, and the anchor may itself have changed. If the source has no extracted statements, the counterpart citation uses relation: "absence" with page and quote both null; an absence cannot be proved by quoting a page.
Native text pages are numbered from one using supplied form-feed boundaries. Citation quotations preserve internal whitespace from extracted statements; the comparison normalizes whitespace. PDF quotations come from extracted text, so reading order, whitespace, columns, and tables can differ from the visible layout.
Output example
The following illustrative successful record shows the shape of a deadline modification. The quotations match the input above. Exact IDs, explanation text, and proposal-section suggestions are generated by the Actor's rules.
{"status": "success","amendmentIndex": 1,"comparisonMode": "replacement","sources": {"original": {"name": "Original RFP","url": null,"type": "text","pageCount": 1,"noTextPages": [],"statementCount": 1},"amendment": {"name": "Amendment 1","url": null,"type": "text","pageCount": 1,"noTextPages": [],"statementCount": 1}},"summary": {"totalChanges": 1,"returnedChanges": 1,"truncatedChanges": 0,"added": 0,"removed": 0,"modified": 1,"requirements": 0,"deadlines": 1,"other": 0,"filteredBoilerplate": 0},"changes": [{"id": "change-1","type": "modified","category": "deadline","severity": "high","assessmentMethod": "deterministic-rules","severityReason": "Deadline language was detected; verify the official date and submission instructions.","proposalSections": ["Submission schedule and compliance checklist"],"suggestionsAreHeuristic": true,"matchMethod": "token-similarity","before": "Proposals must be received by 15 October 2026 at 17:00 UTC.","after": "Proposals must be received by 22 October 2026 at 17:00 UTC.","citations": {"original": {"source": "original","name": "Original RFP","url": null,"page": 1,"quote": "Proposals must be received by 15 October 2026 at 17:00 UTC.","relation": "changed-text"},"amendment": {"source": "amendment","name": "Amendment 1","url": null,"page": 1,"quote": "Proposals must be received by 22 October 2026 at 17:00 UTC.","relation": "changed-text"}}}],"warnings": [],"limitations": ["Classifications and proposal-section suggestions use deterministic heuristics and require human review."]}
Live test notes (2026-10-13)
Build 1.0.9 was checked against real public procurement documents:
- Rhode Island Commerce RFP-2616 (13-page PDF) vs Addendum 1 and Addendum 2 (addendum mode, one run): Addendum 1 returned exactly one change, the corrected proposal deadline ("…corrected to 11:59 pm, Friday, October 16, 2026."), with 9 boilerplate statements omitted; Addendum 2 returned exactly its two corrected question/response deadlines.
- Siskiyou County RFP 26-2060-01 vs Addendum 1: 14 changes, 10 of them deadlines; each revised schedule row pairs with the same event in the original (proposal due October 6 → October 13, questions → September 30, interviews October 19–21 → October 20).
- Siskiyou RFP vs an edited full revision (replacement mode, native text): all five edits found with page citations (two moved deadlines, an added license requirement, a "shall" → "may" change, an insurance amount change) and nothing else.
- An HTML page URL returned an
UNSUPPORTED_DOCUMENTerror and noresultcharge.
Heuristic limits remain: a schedule row whose original label was not extracted may appear as an addition rather than a modification, and short instructions such as "The Estimated Timeline … is deleted and replaced" are kept for review.
Limitations and review
The comparison operates on extracted statements rather than document layout. Formatting-only changes, images, signatures, scanned pages, and differences lost during extraction may not be detected. Replacement mode compares statement order, so moving unchanged wording can appear as a removal and an addition. PDF table and column reading order can affect matching. Exact matching and token similarity do not understand cross-references, precedence rules, exceptions, negation, or the contractual effect of an amendment.
Review the cited passages in the source documents, inspect warnings, and confirm deadline and requirement changes before updating a proposal. An empty change list means no statement changes were detected within these limits; it is not a compliance determination.
Billing
Each successful amendment comparison emits one custom result event for Apify pay-per-event billing. Successful comparisons with zero detected changes are charged, including identical or empty native-text documents; the charge is not per changed clause. Error records do not emit that event. The price is set in the Actor's Store pricing configuration; consult the Store listing for the current rate and any platform costs.
Local use and deployment
From this Actor's directory:
npm installmkdir -p storage/key_value_stores/defaultcp INPUT.example.json storage/key_value_stores/default/INPUT.jsonnpm start
Node.js 24 or newer is required. With the same local input file, an Apify CLI workflow can use apify run. Use apify push to deploy to your own account. Configure the Store listing and the result event price in Apify before offering the Actor for sale; this repository does not set a customer price or publish a Store listing.
Live example run
This is real output from a cloud run of the Actor's default (prefilled) input on 2026-10-16. Just click Start to reproduce it.
- Full example dataset (public, JSON): https://api.apify.com/v2/datasets/qZXUDZVVawHRWOaPE/items?clean=1&format=json
Input:
{"original": {"name": "Original RFP","text": "Proposals must be received by 15 October 2026 at 17:00 UTC."},"amendments": [{"name": "Amendment 1","text": "Proposals must be received by 22 October 2026 at 17:00 UTC."}]}
Output (first item; long arrays shortened):
{"status": "success","amendmentIndex": 1,"comparisonMode": "replacement","sources": {"original": {"name": "Original RFP","url": null,"type": "text","pageCount": 1,"noTextPages": [],"statementCount": 1},"amendment": {"name": "Amendment 1","url": null,"type": "text","pageCount": 1,"noTextPages": [],"statementCount": 1}},"summary": {"totalChanges": 1,"returnedChanges": 1,"truncatedChanges": 0,"added": 0,"removed": 0,"modified": 1,"requirements": 0,"deadlines": 1,"other": 0,"filteredBoilerplate": 0},"changes": [{"id": "change-1","type": "modified","category": "deadline","severity": "high","severityReason": "A date or time differs between the cited passages or is stated as revised; verify the official schedule.","proposalSections": ["Submission schedule and compliance checklist"],"assessmentMethod": "deterministic-rules","suggestionsAreHeuristic": true,"matchMethod": "token-similarity","similarityScore": 0.944,"before": "Proposals must be received by 15 October 2026 at 17:00 UTC.","after": "Proposals must be received by 22 October 2026 at 17:00 UTC.","citations": {"original": {"source": "original","name": "Original RFP","url": null,"page": 1,"quote": "Proposals must be received by 15 October 2026 at 17:00 UTC.","relation": "changed-text"},"amendment": {"source": "amendment","name": "Amendment 1","url": null,"page": 1,"quote": "Proposals must be received by 22 October 2026 at 17:00 UTC.","relation": "changed-text"}}}],"warnings": [],"limitations": ["Compares each amendment independently against the original; does not apply a cumulative amendment history.","Whitespace is normalized. Comparison uses extracted statements, not PDF layout, tables, images, or handwritten marks.","Replacement mode compares statement order; moving unchanged wording can appear as a removal and an addition.","…"]}