jake142 / receiptscanner
ReceiptScanner is a Laravel AI provider wrapper for scanning receipt images and PDFs into structured receipt JSON via OpenAI, Azure OpenAI, Gemini, and Anthropic provider APIs.
Requires
- php: ^8.3
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0|^11.0
- phpunit/phpunit: ^11.0|^12.0
README
ReceiptScanner is a small Laravel package for extracting structured receipt data from images and PDFs using upstream AI providers.
It is a wrapper around multimodal LLM APIs. It does not host its own OCR service, database, queue, UI, or REST API.
Features
- Laravel facade entry point:
Jake142\ReceiptScanner\Facades\ReceiptScanner - Public methods:
ReceiptScanner::scanImages(array $images): arrayReceiptScanner::scanPdf(mixed $pdf): array
- Supports multi-image receipt analysis in a single upstream request
- Supports PDF receipt analysis from one input file
- Provider selection via config/env
- Default provider models:
- OpenAI:
gpt-5.4-nano - Azure OpenAI:
gpt-5.4-nano - Gemini:
gemini-2.5-pro - Anthropic:
claude-sonnet-4-20250514
- OpenAI:
- Configurable output fields to reduce prompt size and response size
- Safe logging controls
Requirements
- PHP
^8.3 - Laravel
illuminate/support^11.0|^12.0|^13.0 - Laravel
illuminate/http^11.0|^12.0|^13.0 - For development and testing:
orchestra/testbench^9.0|^10.0|^11.0
Installation
composer require jake142/receiptscanner
Publish the config file:
php artisan vendor:publish --tag=receiptscanner-config
Configuration
ReceiptScanner is configured through config/receipt-scanner.php and environment variables.
Environment variables
RECEIPT_SCANNER_PROVIDER=openai RECEIPT_SCANNER_TIMEOUT=60 RECEIPT_SCANNER_MAX_RETRIES=2 RECEIPT_SCANNER_PROMPT_LANGUAGE=en OPENAI_API_KEY= OPENAI_MODEL=gpt-5.4-nano AZURE_OPENAI_API_KEY= AZURE_OPENAI_ENDPOINT= AZURE_OPENAI_DEPLOYMENT=gpt-5.4-nano AZURE_OPENAI_MODEL=gpt-5.4-nano GEMINI_API_KEY= GEMINI_MODEL=gemini-2.5-pro ANTHROPIC_API_KEY= ANTHROPIC_MODEL=claude-sonnet-4-20250514
Config shape
The package config exposes these keys:
default_providerproviders.openai.api_keyproviders.openai.modelproviders.azure_openai.api_keyproviders.azure_openai.endpointproviders.azure_openai.deploymentproviders.azure_openai.modelproviders.gemini.api_keyproviders.gemini.modelproviders.anthropic.api_keyproviders.anthropic.modeltimeoutmax_retriesenabled_fieldsprompt_language
Default output fields
By default, all fields are enabled:
merchanttotal_amountcurrencydatevat_amountmccvatsline_itemsconfidencetippurchase_countrypurchase_city
You can disable parts of the response in config to reduce prompt size and response size. For example, if you do not need VAT breakdowns, set enabled_fields.vats to false.
Usage
Scan multiple images
Use scanImages() when a receipt is split across several photos.
use Jake142\ReceiptScanner\Facades\ReceiptScanner; $result = ReceiptScanner::scanImages([ storage_path('app/receipts/receipt-part-1.jpg'), storage_path('app/receipts/receipt-part-2.jpg'), ]);
The images are analyzed together as one receipt. This is useful when the top and bottom of a long receipt were captured in separate photos.
Scan a PDF
Use scanPdf() for a single PDF input.
use Jake142\ReceiptScanner\Facades\ReceiptScanner; $result = ReceiptScanner::scanPdf(storage_path('app/receipts/receipt.pdf'));
Result format
$result is a JSON-compatible associative array. The package asks the upstream model to return strict JSON only.
Default output shape:
[
'merchant' => null,
'total_amount' => null,
'currency' => null,
'date' => null,
'vat_amount' => null,
'mcc' => null,
'vats' => [
[
'rate' => null,
'amount' => null,
'amount_inc_vat' => null,
'amount_ex_vat' => null,
],
],
'line_items' => [
[
'description' => null,
'quantity' => null,
'unit_price' => null,
'amount' => null,
],
],
'confidence' => null,
'tip' => null,
'purchase_country' => null,
'purchase_city' => null,
]
Notes:
vatsis always an array.line_itemsis always an array.- Unknown scalar values are returned as
null. - Unknown arrays are returned as
[]. - Dates are normalized to
YYYY-MM-DDwhen possible. - Numeric values are normalized to numbers, not strings, when possible.
mccis AI-estimated because receipts usually do not contain MCC directly.tipis a numeric tip/gratuity amount when visible on the receipt; otherwisenull.purchase_countryis the purchase country when inferable from receipt text, merchant/address, currency, or visible location; otherwisenull.purchase_cityis the purchase city when visible or clearly inferable from receipt text/address; otherwisenull.
Provider selection
Set the provider and model in env, then load them through config.
Example:
RECEIPT_SCANNER_PROVIDER=openai OPENAI_MODEL=gpt-5.4-nano
Azure OpenAI is supported as well. When using Azure OpenAI, configure the Azure provider settings and use the OpenAI gpt-5.4-nano model/deployment.
Logging
If logging is enabled, the package may log safe diagnostics such as provider, model, mime type, retry count, duration, and failure category.
It will not log API keys, raw receipt contents, extracted JSON values, or full base64 payloads.
Error handling
The package throws Jake142\ReceiptScanner\Exceptions\ReceiptScannerException for configuration, input, upstream, and parsing failures.
Testing
No tests are included in this package.
Disclaimer
ReceiptScanner uses upstream AI providers to interpret receipts. It does not guarantee accounting accuracy. Always review critical financial data before using it in production workflows.