RFP Amendment and Addendum Analyzer avatar

RFP Amendment and Addendum Analyzer

Pricing

$250.00 / 1,000 rfp amendment comparisons

Go to Apify Store
RFP Amendment and Addendum Analyzer

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

Nicholas Tamagni

Maintained by Community

Actor 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 suppliedSet comparisonModeExpected JSON changes
Original plus a complete revised versionreplacementStatement additions, removals, and suggested modifications between the two versions.
Original plus a separate amendment or supplementaddendumNew 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

FieldRequiredMeaning
originalYesDocument object with exactly one of text or url, and optional name.
amendmentsYesArray of 1 to 50 document objects with the same shape as original.
comparisonModeNoreplacement (default) or addendum.
maxChangesNoMaximum returned changes per amendment, from 1 to 2,000; default 500.
includeBoilerplateNoAddendum 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 text supports plain text and Markdown. A form-feed character, written as \f inside JSON strings, marks a page boundary. Empty native documents are valid; two empty or otherwise identical documents yield zero changes.
  • A url must 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:

FieldMeaning
statussuccess; failed records use error and include error.code and error.message.
amendmentIndexThe amendment's 1-based position in the input array. A global error can use null.
sources.original, sources.amendmentSource metadata: name, url, type, pageCount, noTextPages, and statementCount.
comparisonModeThe selected comparison mode.
summaryCounts: totalChanges, returnedChanges, truncatedChanges, added, removed, modified, requirements, deadlines, other, and filteredBoilerplate (addendum-mode statements omitted as boilerplate).
changesReturned changes, each with before/after text, classification, matching method, and source citations.
warningsIssues affecting interpretation, such as PDF pages with no extractable text.
limitationsQualifications 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:

  • id and type (added, removed, or modified). before or after is null when that side has no changed statement.
  • category (deadline, requirement, or other) and severity (high, medium, or low), with a severityReason. These are rule-based review cues, not measures of contractual importance.
  • assessmentMethod: "deterministic-rules", suggestionsAreHeuristic: true, and a proposalSections array suggesting sections to inspect.
  • matchMethod: exact-sequence, token-similarity, or addendum-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.original and citations.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_DOCUMENT error and no result charge.

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 install
mkdir -p storage/key_value_stores/default
cp INPUT.example.json storage/key_value_stores/default/INPUT.json
npm 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.

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.",
"…"
]
}