Business PDF Field Extractor
Pricing
from $8.50 / 1,000 document rows
Business PDF Field Extractor
Give PDF addresses and get fixed fields back: invoice and purchase order numbers, dates, parties, totals, and line items, plus contract parties, dates, term, renewal, notice, and governing law. Reads scans with OCR. No AI and no API key.
Pricing
from $8.50 / 1,000 document rows
Rating
0.0
(0)
Developer
Mamba Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 hours ago
Last modified
Categories
Features
Share
Give PDF addresses and get fixed fields back as rows. Invoices and purchase orders return numbers, dates, parties, totals, line items, and a check that the amounts add up. Contracts return parties, dates, term, renewal, notice days, governing law, and which standard clauses appear. Text PDFs and scans both work. You pay per document read, and Mamba Labs pays the platform costs.
Features
- The same columns on every run. Text extractors return a page of text; this returns
document_number,total,due_date, and so on, so a table or a Clay column does not change shape between files. - Line items. Read from the table on the document, across pages when the header repeats, as a
line_itemsfield and as free rows. - A totals check.
totals_checksays whether subtotal, tax, shipping, and discount add up to the total. Amismatchtells you to look at that document. - It says what it did not find.
fields_foundandfields_missingare on each row. A missing value is null, never a guess. - Contract triage. Parties, effective and end dates, term wording, renewal, termination and renewal notice days, governing law, contract value, bid due date, and 16 standard clause types with an excerpt and page number.
template_placeholderscounts blanks, so an unfilled template is visible. - Scans. A page with no text layer goes through OCR at 200 dpi, charged per page, with a per file cap.
- Label words beyond English for invoices and purchase orders: Dutch, German, and French were tested on real samples; Spanish and Italian labels are in the rules but were not tested. Contract rules read English only.
- No AI and no API key. The same file gives the same output, and your documents go to no outside service.
How the data is read
The actor downloads each address directly, and retries through the Apify proxy pool if the host refuses that. It never uses residential proxies. Poppler reads the text layer with its column layout, and Tesseract reads scanned pages, both inside the run. Fields come from known labels and column position. No login, no key, no AI, and no other developer's actor. Document text is not written to the log.
Input
| Field | Type | Default | What it does |
|---|---|---|---|
pdf_urls | array | Web addresses of PDF files, up to 1,000. Each file up to 40 MB. The address must answer without a login. In Clay, put the column in a one item list. | |
pdf_file | string | Optional. One PDF file from your computer, stored in your Apify account. | |
document_type | string | auto | auto (default) works it out per file. Set invoice, purchase_order, or contract to read every file as that type. |
date_order | string | mdy | How to read a date such as 03/04/2025 when both readings are valid. mdy (default) reads March 4, dmy reads 3 April. Unambiguous dates ignore this. |
read_scans | string | yes | yes (default): a page with no text layer goes through OCR, charged per page. no: those pages are skipped and the row says so. |
ocr_language | string | eng | Language of scanned pages: eng (default), deu, fra, spa, nld, ita, or por. |
max_pages | string | 50 | Pages to read per file, up to 500. Default 50. |
max_ocr_pages | string | 10 | Scanned pages to read per file, up to 100. Default 10. This caps the OCR charge per file. |
max_documents | string | 100 | Files to read in this run, up to 1,000. Default 100. |
line_item_rows | string | yes | yes (default): each line item is also its own free row, which suits CSV and Clay. no: line items stay in the line_items field only. |
include_text | string | no | yes: add the document text to the row, up to 200,000 characters. Default no. |
max_charge_usd | string | Optional. The run stops before a charge that would pass this amount. Summary rows are always returned. |
Output
| Field | Type | What it holds |
|---|---|---|
row_type | string | One of: document, line_item, ocr_page, run_summary. run_summary is the one free row written when the input is refused. |
file_url | string | The address this row came from. |
document_type | string | invoice, purchase_order, contract, or other. Other returns no fields. |
pages_total | integer | Pages the PDF reports. |
pages_read | integer | Pages whose text was read, from the text layer or OCR. |
pages_ocr | integer | Scanned pages read by OCR. Each one is charged as ocr-page. |
text_source | string | text_layer, ocr, mixed, or none. |
page_number | integer | On an ocr_page row: the page that was read. |
document_number | string | Invoice number or purchase order number. |
document_date | string | Invoice date or order date as YYYY-MM-DD. |
due_date | string | Payment due date as YYYY-MM-DD. Invoices. |
delivery_date | string | Requested delivery date as YYYY-MM-DD. Purchase orders. |
po_number | string | The purchase order or order number the document cites. |
seller_name | string | The issuer on an invoice, the supplier on a purchase order. |
seller_address | string | The address lines under the seller, when labeled. |
seller_tax_id | string | A VAT, GST, EIN, or ABN value next to its label. |
buyer_name | string | The billed party on an invoice, the ordering party on a purchase order. |
buyer_address | string | The address lines under the buyer, when labeled. |
ship_to | string | The ship to or deliver to block. |
payment_terms | string | Payment terms as written, such as Net 30. |
currency | string | ISO code, from a code or symbol on the document. A bare $ reads as USD. |
subtotal | number | Amount before tax. |
discount | number | Document level discount. |
tax | number | Tax amount. |
shipping | number | Shipping or freight amount. |
total | number | Document total. |
amount_due | number | Amount or balance due, when stated apart from the total. |
line_items | array | Line items on the document row: line_number, item_code, description, quantity, unit, unit_price, discount, tax_rate, amount. |
line_item_count | integer | How many line items were read. |
totals_check | string | match: subtotal plus tax and shipping less discount, or the line items, equal the total. lines_differ: the header adds up but the line items do not, so some lines were probably not read. mismatch: the amounts do not add up. not_checked: too few amounts were read. |
line_items_sum | number | The line item amounts added up. |
line_number | integer | On a line_item row: position in the table. |
item_code | string | On a line_item row: SKU, part number, or item code. |
description | string | On a line_item row: the item description. |
quantity | number | On a line_item row: quantity. |
unit | string | On a line_item row: unit of measure. |
unit_price | number | On a line_item row: price per unit. |
line_discount | string | On a line_item row: discount as written. |
tax_rate | string | On a line_item row: tax rate as written. |
line_amount | number | On a line_item row: line total. |
contract_title | string | The title line of a contract or bid document. |
parties | array | Party names from the by and between sentence or defined party labels. |
effective_date | string | Contract effective date as YYYY-MM-DD. |
expiration_date | string | Stated end date as YYYY-MM-DD. Null when the term is only a duration. |
term_text | string | The sentence that states the term, up to 400 characters. |
term_months | integer | The term in months when the wording states a duration. |
renewal | string | automatic, optional, or none_found, from the wording. |
termination_notice_days | integer | Days of notice in the first sentence about termination that states them. |
renewal_notice_days | integer | Days of notice in the first sentence about renewal that states them. |
governing_law | string | The jurisdiction named in the governing law wording. |
contract_value | number | An amount next to wording such as total contract price, fixed fee, or not to exceed. |
bid_due_date | string | Proposal or bid submission date as YYYY-MM-DD, on a bid document. |
clauses_found | array | Which of 16 standard clause types appear in the wording. Keyword rules, not legal review. |
clause_excerpts | array | For each clause found: clause, page, and an excerpt of up to 300 characters. |
template_placeholders | integer | Count of blanks and insert markers. A high count means an unfilled template. |
fields_found | array | The fields for this document type that hold a value. |
fields_missing | array | The fields for this document type that were not found on the document. |
full_text | string | The text of the document up to 200,000 characters, only with include_text yes. |
row_status | string | ok, or why this row carries no data: no_results, no_change, partial, blocked, or error. |
error_reason | string | Why the row is not ok. A refused input reads input_invalid: followed by what to fix. |
billable_events_json | string | What this row was billed as, for example {"document-row":1}. {} means free. |
scraped_at | string | When the row was written, UTC. |
Pricing
Pay per event. You pay for each PDF with at least one field read, each scanned page read by OCR, and the run start. Line item rows, a document with no fields read, a failed download, and a refused input are free.
| Event | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|
document-row, one PDF with at least one field read | $0.01 | $0.0095 | $0.009 | $0.0085 |
ocr-page, one scanned page read by OCR, charged when OCR returned text | $0.015 | $0.01425 | $0.0135 | $0.01275 |
apify-actor-start, once per run (one per GB of memory; the default 1024 MB is one) | $0.004 | $0.004 | $0.004 | $0.004 |
Per 1,000 rows of document-row: $10.00 on the free plan, $8.50 on Gold.
Free plan cap: 1.50 USD of evaluation a month, about 150 rows. Any paid Apify plan removes the cap, and it resets on the 1st. The run stops before a charge that passes your maximum charge per run in Apify or your max_charge_usd input.
Mamba Labs pays the platform costs of your run, Apify proxy traffic included.
Usage examples
Invoices and purchase orders.
{"pdf_urls": ["https://docs.oasis-open.org/ubl/cd-UBL-1.0/fs/Order/pdf/OfficeOrder.Example-us.pdf"],"document_type": "auto"}
European invoices. Set date_order to dmy so 03/04/2025 reads as 3 April.
Clay. Number and on or off inputs are text fields, which is what Clay sends. A list input takes a JSON list, so put the column inside a one item list.
MCP. The Mamba Labs MCP server @mambalabsdev/mcp-business-pdf-field-extractor exposes this actor to Claude and other MCP clients.
Error handling
| Case | What you get |
|---|---|
| Missing or unreadable input | One free row, row_type run_summary, error_reason starting input_invalid: with what to fix. The run ends successfully and charges nothing but the run start |
| Download failed, not a PDF, over 40 MB, or a password | One free document row with row_status error or blocked and the reason |
| No field label found, or a type this actor does not read | One free document row with row_status no_results. OCR pages already read stay charged |
Pages left unread by max_pages or max_ocr_pages | row_status partial, charged, and error_reason says how many |
| The run is close to its timeout | The actor stops starting new work 90 seconds before the timeout and delivers what it has |
Limitations
- Fields come from labels and column position, with no AI. On a layout with unusual labels a value can be missing, and on a crowded layout it can be wrong. Check
totals_checkandfields_missing, and review before you pay or sign anything. - Seller and buyer names are the least reliable fields. A name with no label next to it is taken from a company suffix such as Inc or B.V., and a name inside a logo image on a text page is not read.
- Line items need a header row with column names. A list of charges with no table header returns no line items.
- OCR accuracy follows scan quality. Skewed or low resolution pages read poorly, handwriting is not supported, and a single digit inside a bordered table cell can be lost, which leaves
quantitynull on that row. English and Dutch scans were tested; the other OCR languages are installed but were not tested. - Clause detection finds keywords in the wording. It is not legal review, and it can flag a clause that is only mentioned in passing.
- A bare
$reads as USD, so Canadian or Australian dollars need the code on the document. - Tested on 11 invoices from a public parser test set, 6 sample purchase orders, and 6 published contract templates. Filled contracts were tested on one document written for the test. Bank statements are out of scope and return no fields.
- The address must answer without a login. Files over 40 MB are refused.
Mamba Labs actor suite
Built by Mamba Labs.