AI Receipt Scanner & OCR avatar

AI Receipt Scanner & OCR

Under maintenance

Pricing

Pay per usage

Go to Apify Store
AI Receipt Scanner & OCR

AI Receipt Scanner & OCR

Under maintenance

Extract line items, totals, taxes, dates, currency, payment details, and more from receipt and invoice images into validated JSON.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Artur Malev

Artur Malev

Maintained by Community

Actor stats

0

Bookmarked

19

Total users

0

Monthly active users

23 days ago

Last modified

Share

Receipt & Invoice Parser API

Receipt OCR/parser and invoice OCR/parser for images and PDF invoices. Turn a receipt image, a single-page invoice, or a multipage PDF invoice into validated, structured JSON for finance, expense, bookkeeping, procurement, and automation workflows.

The Actor accepts public HTTP(S) URLs (or an Apify fileupload source delivered as a URL string), sends one ordered request per logical document, validates the result against the canonical v0.2 contract, and returns exactly one dataset item per input source. Missing or unreadable values become null; the model is never allowed to author the final validation block.

Pricing

$0.01 per successfully processed logical document.

One receipt image, one single-page invoice, or one multipage PDF is one logical document and one charge. A valid result with validation.needsReview: true is still a successful document and is charged once.

Not charged:

  • invalid or unsafe sources;
  • download, timeout, or unsupported-format failures;
  • provider, JSON-parse, or schema-validation failures;
  • rows with no structured result;
  • extra pages, retries, or duplicate/coalesced work.

The Apify Store Pricing tab is the source of truth for billing; standard Apify platform/storage charges may apply according to your plan.

This Actor is not yet published. Publication is blocked until a measured benchmark passes the approved cost caps and a ≥40% net average contribution margin after Apify commission. The pricing above is the intended unit; no measured economics are claimed here.

What you get

  • Receipt & invoice classification — documentType is receipt or invoice, with schemaVersion "0.2".
  • Receipt extraction — merchant details, dates, currencies, line items (name, quantity, unit price, total price, discounts, SKU, barcode), totals, payment details, receipt IDs, loyalty, promotions, return policy, warranty, and gift-receipt fields.
  • Invoice extraction — invoice number, purchase order, issue/due/service dates, supplier and customer, payment terms, amount due, and a VAT/tax breakdown with type, rate, taxable amount, and tax amount.
  • Raw text — rawText preserves readable document text, or null when none is readable.
  • Deterministic validation — validation.status (passed / failed / insufficient_data), typed checks, needsReview, and reviewReasons. Non-evaluable arithmetic is reported separately and never counted as a pass.
  • Stable JSON output — strict canonical schema; unknown fields are rejected.
  • Batch processing — up to 20 documents per run with configurable concurrency.

Supported inputs and limits

  • Formats: JPEG, PNG, WebP, and non-encrypted PDF (detected by magic bytes, not file extension).
  • PDF: up to 20 pages; all pages are sent as one ordered logical document.
  • Download: public HTTP(S) only, 20 MiB max, 30-second timeout, up to five redirects.
  • Images: 40 MP decoded max, longest normalized side 2500 px, 30 MiB normalized aggregate.
  • Batch: up to 20 documents per run; maxConcurrent up to 5.
  • Privacy/safety: private, local, credentialed, and redirect-escaping URLs are rejected. Raw URL query strings and document bytes never appear in error messages or logs.

Input fields:

{
"receiptUrl": "https://example.com/receipt.jpg"
}
{
"receiptUrls": [
"https://example.com/receipt-1.jpg",
"https://example.com/invoice.pdf"
],
"maxConcurrent": 5
}

receiptUrl, receiptUrls, and fileupload are supported. fileupload is delivered as a string source and is resolved through the same HTTP(S) path; a non-URL string is rejected explicitly. Provide at least one source.

Example output

Receipt result

{
"url": "https://example.com/receipt.jpg",
"cached": false,
"data": {
"schemaVersion": "0.2",
"documentType": "receipt",
"rawText": "EXAMPLE MARKET\n12 Market Street\n2026-09-14 18:42\nWhole Milk 1L 2 x 1.79 3.58\nBread 1 x 2.20 2.20\nSUBTOTAL 5.78 TAX 0.68 TOTAL 6.46\nVISA ****4242",
"store": {
"name": "Example Market",
"address": "12 Market Street",
"date": "2026-09-14",
"time": "18:42",
"currency": "EUR",
"phone": null,
"website": null,
"store_id": null
},
"items": [
{
"name": "Whole Milk 1L",
"category": null,
"quantity": 2,
"unit_price": 1.79,
"total_price": 3.58,
"discount": null,
"discount_rate": null,
"sku": null,
"barcode": null
},
{
"name": "Bread",
"category": null,
"quantity": 1,
"unit_price": 2.2,
"total_price": 2.2,
"discount": null,
"discount_rate": null,
"sku": null,
"barcode": null
}
],
"totals": {
"subtotal": 5.78,
"tax": 0.68,
"total": 6.46,
"currency": "EUR"
},
"payment": {
"method": "card",
"card_type": "Visa",
"card_last_digits": "4242",
"transaction_id": null,
"authorization_code": null
},
"receipt": {
"receipt_id": "R-000123",
"cashier_id": null,
"register_id": "3",
"order_number": null,
"loyalty_info": null,
"qr_code": null,
"barcode": null
},
"invoice": null,
"loyalty": {
"program_name": null,
"member_id": null,
"points_earned": null,
"points_balance": null,
"tier_status": null,
"expiration_date": null
},
"return_policy": {
"days_allowed": 30,
"conditions": "Original packaging required.",
"receipt_required": true,
"restocking_fee": null,
"exceptions": null
},
"warranty": {
"duration": null,
"coverage": null,
"contact_info": null,
"conditions": null,
"product_registration": null
},
"gift_receipt": {
"is_gift_receipt": false,
"gift_message": null,
"gift_from": null,
"gift_to": null,
"gift_occasion": null
},
"promotions": {
"promo_codes": [],
"future_discounts": null,
"special_offers": null,
"expiration_dates": null,
"conditions": null
},
"metadata": {
"confidence_score": 0.97,
"ocr_quality": "high"
},
"validation": {
"status": "passed",
"checks": [
{
"code": "LINE_ITEMS_INCOMPLETE",
"status": "passed",
"message": "All line item totals match quantity times unit price."
},
{
"code": "TOTAL_MISMATCH",
"status": "passed",
"message": "Subtotal plus tax matches total."
}
],
"needsReview": false,
"reviewReasons": []
}
}
}

Invoice result

{
"url": "https://example.com/invoice.pdf",
"cached": false,
"data": {
"schemaVersion": "0.2",
"documentType": "invoice",
"rawText": "ACME SUPPLIES\n1 Industrial Way\nInvoice INV-2026-0042\nIssue 2026-09-01 Due 2026-09-30\nConsulting 100.00\nVAT 19% 19.00\nAMOUNT DUE 119.00 EUR",
"store": {
"name": "Acme Supplies",
"address": "1 Industrial Way",
"date": "2026-09-01",
"time": null,
"currency": "EUR",
"phone": null,
"website": null,
"store_id": null
},
"items": [
{
"name": "Consulting",
"category": null,
"quantity": 1,
"unit_price": 100.0,
"total_price": 100.0,
"discount": null,
"discount_rate": null,
"sku": null,
"barcode": null
}
],
"totals": {
"subtotal": 100.0,
"tax": 19.0,
"total": 119.0,
"currency": "EUR"
},
"payment": {
"method": "bank_transfer",
"card_type": null,
"card_last_digits": null,
"transaction_id": null,
"authorization_code": null
},
"receipt": {
"receipt_id": null,
"cashier_id": null,
"register_id": null,
"order_number": null,
"loyalty_info": null,
"qr_code": null,
"barcode": null
},
"invoice": {
"invoiceNumber": "INV-2026-0042",
"purchaseOrderNumber": "PO-7781",
"issueDate": "2026-09-01",
"dueDate": "2026-09-30",
"serviceDate": "2026-09-01",
"supplier": {
"name": "Acme Supplies",
"address": "1 Industrial Way",
"taxId": "DE123456789"
},
"customer": {
"name": "Example Market",
"address": "12 Market Street",
"taxId": "DE987654321"
},
"paymentTerms": "Net 30",
"amountDue": 119.0,
"taxBreakdown": [
{
"taxType": "VAT",
"rate": 0.19,
"taxableAmount": 100.0,
"taxAmount": 19.0
}
]
},
"loyalty": {
"program_name": null,
"member_id": null,
"points_earned": null,
"points_balance": null,
"tier_status": null,
"expiration_date": null
},
"return_policy": {
"days_allowed": null,
"conditions": null,
"receipt_required": null,
"restocking_fee": null,
"exceptions": null
},
"warranty": {
"duration": null,
"coverage": null,
"contact_info": null,
"conditions": null,
"product_registration": null
},
"gift_receipt": {
"is_gift_receipt": null,
"gift_message": null,
"gift_from": null,
"gift_to": null,
"gift_occasion": null
},
"promotions": {
"promo_codes": null,
"future_discounts": null,
"special_offers": null,
"expiration_dates": null,
"conditions": null
},
"metadata": {
"confidence_score": 0.98,
"ocr_quality": "high"
},
"validation": {
"status": "passed",
"checks": [
{
"code": "LINE_ITEMS_INCOMPLETE",
"status": "passed",
"message": "All line item totals match quantity times unit price."
},
{
"code": "TOTAL_MISMATCH",
"status": "passed",
"message": "Subtotal plus tax matches total."
},
{
"code": "TAX_MISMATCH",
"status": "passed",
"message": "Tax breakdown matches totals tax."
}
],
"needsReview": false,
"reviewReasons": []
}
}
}

Review signals and failures

Validation is deterministic and computed locally from extracted values. It never alters extracted data.

  • validation.status is passed, failed, or insufficient_data.
  • validation.checks lists typed outcomes; validation.reviewReasons carries stable codes: TOTAL_MISMATCH, LINE_ITEMS_INCOMPLETE, TAX_MISMATCH, UNREADABLE_FIELD.
  • validation.needsReview is true when any check is not passed. A needsReview result is still a successful, charged document.
  • Arithmetic that cannot be evaluated (missing operands) is reported as insufficient_data and excluded from the pass denominator — never silently passed.

If a source cannot be processed, the Actor returns an error row and does not charge:

{
"url": "https://example.com/not-a-document.jpg",
"cached": false,
"error": {
"code": "PROCESSING_FAILED",
"message": "The receipt could not be processed. Please try again."
}
}

Stable ingestion error codes include MALFORMED_SOURCE, UNSAFE_SOURCE, INACCESSIBLE_SOURCE, UNSUPPORTED_SOURCE, BROKEN_SOURCE, ENCRYPTED_SOURCE, EMPTY_SOURCE, OVERSIZE_SOURCE, and OVER_PAGE_LIMIT. Post-provider processing failures use PROCESSING_FAILED for JSON-parse, schema-validation, and unexpected errors. Provider-specific errors use PROVIDER_* codes.

How it works

Each source is downloaded once, normalized into ordered JPEG pages (images become one page; PDFs render one page per page), and sent as a single provider request. Exactly one inference is made per logical document; duplicates within a run are coalesced. The result is normalized and validated against the canonical v0.2 schema, and one dataset item is returned per input source. The cache is scoped to the current Actor run only; document contents are not stored in a shared cross-user cache.

Developers

The output contract is defined in src/receipt_schema.json. The Actor runs on Apify SDK 4 and exposes results through the standard Apify dataset/API tooling. Quality, latency, hallucination, and cost gates are tracked with the private golden-set benchmark under benchmarks/; see benchmarks/README.md for the approved policy, which is launch policy and not a claim of achieved results.

Limitations

Public HTTP(S) URLs and Apify fileupload URL strings only. No KVS-key upload protocol, no generic-document support, no human review, and no automatic provider retries or fallback. Recognition quality depends on image quality, cropping, lighting, language, and layout. This Actor is intended for data extraction and automation; it is not a fraud-detection, tax-compliance, or legally authoritative document-verification service.

License

MIT