Apify Tender Attachment Parser avatar

Apify Tender Attachment Parser

Pricing

from $25.00 / 1,000 attachment parseds

Go to Apify Store
Apify Tender Attachment Parser

Apify Tender Attachment Parser

Parse SAM.gov and TED tender attachments (PDF, DOCX, XLSX, ZIP) into structured JSON with page-level citations and OCR for scanned files.

Pricing

from $25.00 / 1,000 attachment parseds

Rating

0.0

(0)

Developer

Leon Yu

Leon Yu

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Security

Limited permissions

Share

What does Tender Attachment Parser do?

Tender Attachment Parser turns public-procurement notice attachments into structured JSON. It reads SAM.gov opportunities through the official Get Opportunities API, TED notices through the anonymous TED Search API, or direct file URLs you already have.

It downloads PDF, DOCX, XLSX, legacy DOC, and ZIP files, extracts text with page numbers, and OCRs scanned pages with Tesseract. Key fields, requirements, evaluation criteria, submission instructions, dates, and FAR/DFARS citations each include provenance: {file, page, snippet}.

It does not log into SAM.gov or TED, and it does not bypass anti-bot challenges. Personal contact details are removed from the output.

Why use Tender Attachment Parser?

Small businesses bidding on US federal and EU tenders, and the consultants who support them, need the attachments, not just the notice list. List scrapers stop at the title and deadline. This Actor reads the files those notices point at.

  • Combine SAM.gov notice IDs or filters, a TED query, and your own file URLs in one run.
  • OCR for image-only pages, with the page marked ocr so you can tell it from digital text.
  • Every extracted value cites the file and page it came from.
  • A bad attachment is recorded as status: "error" and the run continues.
  • No paid LLM. Extraction is deterministic. There is no hidden model bill.
  • The document pipeline lives in docpipe/ and does not import the Apify SDK, so a later datasheet Actor can reuse it. See docpipe/README.md.

On Apify you can schedule runs, call the Actor from the API, and download the dataset as JSON, CSV, Excel, or HTML.

What data can Tender Attachment Parser extract?

Each dataset item is one notice. Attachment detail is nested on that item.

FieldWhat it is
title, solicitationNumber, buyerNameTitle, solicitation number, agency or buyer
naics, cpv, naicsOrCpvNAICS and CPV codes
setAsideSet-aside code or description
placeOfPerformanceCity, state, postal code, country. Street addresses from the API are omitted
submissionDeadline, qaDeadline, siteVisitDatesDeadlines and site-visit lines
contractType, procedureType, estimatedValue, periodOfPerformanceContract and procedure text found by rules or returned by the API
fieldsThe same values as a list, each with provenance
outlineSection headings and the text under them
requirementsShall/must statements
evaluationCriteria, submissionInstructions, complianceMatrixLines under those headings
farClausesFAR 52.xxx-x and DFARS 252.xxx-xxxx citations
datesDates, with the label from the same line when there is one
attachmentsPer-file status, page text, OCR pages, and the same sections
statusok, partial, or error

Provenance looks like this:

{"file": "solicitation.pdf", "page": 1, "snippet": "Solicitation Number: W912QR-26-R-0042"}

page is null for a value that came from the SAM.gov or TED API rather than a file. DOCX content is reported as page 1. Each XLSX sheet is one page.

How to parse SAM.gov and TED attachments

  1. Open the Actor input. For SAM.gov, paste your own API key from SAM.gov Account Details. TED search does not use a key.
  2. Add notice IDs, a TED publication number or expert query, and/or direct https file URLs. The three modes can be used together.
  3. Leave OCR on if scans are possible. Set Max notices and Max pages so a wide search stays bounded.
  4. Start the run. Set memory to 1024 MB (the default) and the run timeout to at least 3600 seconds for a batch. One digital file is much faster; OCR is about half a second per scanned page on a small machine.
  5. Open the dataset. The Notices view is the summary table. Download JSON when you need provenance and clauses. The API tab runs the same input from your own code.

SAM.gov only accepts a posted-date window of one year. If you omit the dates, the Actor uses the last 364 days ending today (UTC). A notice older than that needs an explicit window that still covers at most one year.

How much will it cost?

Pricing is pay per event. Amounts are not configured yet. Set them in the Apify Console against the event names below. Do not also enable the built-in apify-default-dataset-item event: this Actor already charges its own events and pushes dataset items without charged_event_name. Enabling both would bill each notice twice.

Placeholder prices, to be replaced when you set Console pricing:

EventWhen it is chargedPlaceholder price
notice-processedA notice was fetched and a record was produced (ok or partial)$0.00 — set in Console
attachment-parsedOne file, or one file inside a ZIP, extracted successfully$0.00 — set in Console

Failed downloads, anti-bot responses, and the SAM.gov notice-description text are not attachment charges. The description is still parsed and shown as a synthetic attachment.

Measured compute

Apify bills the reserved memory for the whole run, not the process RSS. This Actor reserves 1024 MB by default (minimum 1024, maximum 8192). Parse timings below were measured on a 2-vCPU dev machine with Python 3.12 and Tesseract 5.3, using the synthetic fixtures in tests/fixtures/. Peak RSS includes the Python interpreter. A separate entrypoint run (Python 3.12, Tesseract 5.3) peaked at 165 MB RSS for a 40-page letter-size scan and 511 MB RSS for one 36×48 inch scanned sheet. Office files, including a 5 MB DOCX, an 80,000-row XLSX, and a 15 MB digital PDF, stayed under 200 MB.

CaseWall timePeak RSS
Digital PDF, 2 pages, OCR off0.006 s91 MB
Scanned PDF, 1 page, OCR on0.63 s120 MB
Same scanned PDF, OCR off0.002 s91 MB
5 scanned pages, OCR on2.5 ssame class of process

OCR of a clean page is about 0.5 s. A 20-page scan is on the order of 10 s of parsing, plus download time. Digital PDFs are usually limited by the download, not by parsing.

Illustrative compute, if a compute unit is $0.30 per GB-hour (check your plan; this is not a quote):

dollars ≈ 1 GB × seconds / 3600 × 0.30

WorkIllustrative compute3× floor
1 scanned page (0.63 s)$0.00005$0.00015
5 scanned pages (2.5 s)$0.0002$0.0005
A 30 s notice, including downloads, at 1 GB$0.0025$0.0075

Container startup is extra and is not in the table. Price on the value of the JSON as well as this floor. The constants that emit the events are CHARGE_EVENTS_ENABLED, EVENT_NOTICE_PROCESSED (notice-processed), and EVENT_ATTACHMENT_PARSED (attachment-parsed) in tender_attachment_parser/charging.py.

Input

See the input tab for every field. Modes can be combined. At least one of the following is required:

  • SAM.gov. samApiKey (secret) plus notice IDs and/or filters: posted dates, NAICS, title keywords, set-aside, notice type, state, solicitation number. The key is sent only to api.sam.gov and is redacted from logs. Requests are paced to one per second, with backoff on HTTP 429. Daily quota is enforced by SAM.gov and depends on the key's role.
  • TED. tedNoticeNumbers and/or tedQuery (expert search, for example buyer-country=IRL AND publication-date>=20261001). tedPdfLanguage defaults to ENG.
  • Direct URLs. attachmentUrls must be public http or https links. Literal private and metadata addresses are rejected.

Other limits: maxNotices (default 10), maxAttachmentsPerNotice (5), maxFileSizeMb (25), maxPages (40), ocrEnabled (on), ocrLanguages (eng, plus deu, fra, spa, ita in the image), outputSections, downloadTimeoutSecs (60), parseTimeoutSecs (120).

Example input is in examples/input.json. Replace PASTE_YOUR_SAM_GOV_KEY with your own key. Do not commit a real key.

{
"samNoticeIds": ["5b345bbb7127b91a3ad577b203fc6f68"],
"samPostedFrom": "01/01/2026",
"samPostedTo": "10/29/2026",
"tedNoticeNumbers": ["748773-2026"],
"attachmentUrls": ["https://example.com/solicitation.pdf"],
"maxNotices": 10,
"ocrEnabled": true,
"ocrLanguages": ["eng"]
}

Output

You can download the dataset as JSON, CSV, Excel, or HTML. The full fixture run is examples/output-fixtures.json (a digital PDF and the same text as a scanned page). A mocked SAM.gov run, with the contact block removed, is examples/sam-mocked-output.json. A live anonymous TED search is examples/ted-live-sample.json.

This excerpt is the digital fixture, with page text left out for length. The file above has the full pages.

{
"source": "url",
"noticeId": "fixture-solicitation.pdf",
"status": "ok",
"title": "Cloud Hosting and Support Services",
"solicitationNumber": "W912QR-26-R-0042",
"buyerName": "Department of the Navy",
"naicsOrCpv": "541512",
"setAside": "Total Small Business Set-Aside (FAR 19.5)",
"placeOfPerformance": "Norfolk, VA 23511",
"submissionDeadline": "March 15, 2026 2:00 PM Eastern",
"qaDeadline": "March 1, 2026 4:00 PM Eastern",
"siteVisitDates": "February 20, 2026 10:00 AM at Building 12",
"contractType": "Firm-Fixed-Price",
"estimatedValue": "$1,250,000",
"periodOfPerformance": "12 months plus two 12-month options",
"fields": {
"solicitationNumber": [
{
"value": "W912QR-26-R-0042",
"provenance": {
"file": "solicitation.pdf",
"page": 1,
"snippet": "Solicitation Number: W912QR-26-R-0042"
}
}
]
},
"requirements": [
{
"text": "C.1 The contractor shall provide a managed cloud hosting environment.",
"provenance": {
"file": "solicitation.pdf",
"page": 1,
"snippet": "C.1 The contractor shall provide a managed cloud hosting environment."
}
}
],
"farClauses": [
{
"system": "FAR",
"clauseId": "52.212-1",
"provenance": {
"file": "solicitation.pdf",
"page": 2,
"snippet": "This solicitation incorporates FAR 52.212-1 Instructions to Offerors."
}
}
]
}

The scanned fixture in the same file reports "ocrPages": [1].

Pricing events

Events are defined in tender_attachment_parser/charging.py.

  • notice-processed — one charge after a SAM.gov, TED, or direct-URL notice is accepted and the record status is ok or partial. Idempotency key: notice:{source}:{noticeId}.
  • attachment-parsed — one charge per successfully parsed file, including each member of a ZIP. Idempotency key: attachment:{source}:{noticeId}:{index}:{fileName}.

CHARGE_EVENTS_ENABLED turns emission on or off without renaming the events. Leave it True for a published Actor. Locally, with no pay-per-event price configured, Actor.charge logs that the charge was ignored and does not bill. Set ACTOR_TEST_PAY_PER_EVENT=1 only on your own machine if you want a local charging log; do not set it on the platform.

docpipe

docpipe is the reusable package: download, type detection, PDF/DOCX/XLSX/DOC text, OCR, ZIP limits, PII redaction, section and clause segmentation, and provenance. Tender fields (NAICS, set-aside, FAR/DFARS, agency) stay in tender_attachment_parser. The public interface is documented in docpipe/README.md.

docpipe/ # no Apify dependency
tender_attachment_parser/ # Actor entrypoint, SAM.gov, TED, assembly
main.py # python -m tender_attachment_parser
charging.py # pay-per-event names
.actor/ # actor.json, input, dataset, and output schemas
tests/fixtures/ # synthetic PDF, scanned PDF, DOCX, XLSX, ZIP
examples/ # real outputs from those fixtures and from TED

Limitations

  • Rules miss values that are only inside a wrapped paragraph, a text box, or a table that does not become lines. The baseline is deterministic on purpose.
  • OCR quality depends on scan resolution and language. The image includes English, German, French, Spanish, and Italian. Other languages need a new Tesseract package in the Dockerfile.
  • A page is OCR'd when it has no text layer, or when it has fewer than 40 characters and contains an image. Short cover pages with a real text layer are not OCR'd.
  • DOCX has no reliable page numbers. Legacy DOC needs antiword and drops most formatting.
  • ZIP members are capped (30 files, depth 2, 100 MB uncompressed, compression ratio 100 above 10 KB). Path traversal and encrypted members are rejected.
  • Encrypted PDFs fail that file only. A parse timeout returns an error for that file; a stuck native parser thread is not killed, but Tesseract itself is limited to 30 seconds per page.
  • SAM.gov title search matches the notice title, not the attachment body. The API returns the latest active version of a notice.
  • TED buyer attachments are often not hosted by TED. The Search API returns a website PDF link. As of this writing that host answers with an AWS WAF challenge (HTTP 202, empty body) to this client. The Actor records that error and still returns the Search API fields. It does not try to solve the challenge. See examples/ted-live-sample.json.
  • Redaction removes emails, phone numbers with separators, and personal names that follow a label such as Point of Contact, contact point, or contracting officer. It can miss a name that is not labeled, and it can redact a two-word organization that sits in that label slot. DFARS numbers such as 252.204-7012 are kept. Organization names are kept.
  • SAM.gov point-of-contact objects (name, email, phone) are never copied into the output. Street addresses on the place of performance are omitted.

Data sources and legality

The Actor calls only official APIs and the file URLs you supply:

  • SAM.gov: https://api.sam.gov/opportunities/v2/search plus the description URL that the API returns. You supply the key. See the GSA Opportunities API.
  • TED: https://api.ted.europa.eu/v3/notices/search, which does not require a key. See the TED API docs.

Notices are public procurement documents. The Actor does not log into either site and does not scrape pages that sit behind a login or an anti-bot challenge. It does not output personal contact data. Organization names are kept. You are responsible for complying with SAM.gov and TED terms, and with privacy rules if a file still contains personal data the redactor did not recognize.

Our Actors are ethical and do not extract private user data such as personal email addresses. They only read public procurement notices and files you explicitly pass in. Personal data is protected by the GDPR in the European Union and by other laws elsewhere. Do not use the output to build a contact list of individuals. If you are unsure whether your use is legitimate, consult your lawyers. Questions and bugs can go to the Actor's Issues tab.

中文简介

招标附件解析器把美国 SAM.gov 与欧盟 TED 的公开采购公告附件(PDF、DOCX、XLSX、DOC、ZIP)解析成结构化 JSON。扫描件会走 Tesseract OCR。标题、编号、采购人、NAICS/CPV、预留、截止时间、需求条款(shall/must)、评标标准、FAR/DFARS 条款和日期都会带上来源:文件名、页码和原文片段。

不输出个人联系人姓名、邮箱和电话;机构名称会保留。SAM.gov 需要你自己的 API key,TED 搜索接口不需要密钥。规则抽取,默认不调用付费大模型。某个附件失败只会记在该文件的 status 和 error 里,不会让整次运行中断。

文档解析管线在 docpipe/,与招标字段分开,后续做规格书 PDF 解析时可以直接复用。