Extract structured data from receipt photos using AI vision. Plug-and-play for any campaign or project.
https://cudofkdbcfhkdqxxxeje.supabase.co/functions/v1https://api.entryfy.com.na
All requests require a Bearer token in the Authorization header.
Authorization: Bearer rsk_your_api_key_here
Service keys are hashed (SHA-256 + pepper) and stored in the database. Each key is scoped to a campaign — the campaign determines extraction rules, provider overrides, and product tagging.
To generate a new key, use node scripts/hash-service-key.mjs "your-raw-key" and insert the hash into receipt_scanner_api_service_keys.
/extractExtract structured data from a receipt image. Accepts multipart form uploads or JSON with base64/URL.
curl -X POST https://cudofkdbcfhkdqxxxeje.supabase.co/functions/v1/extract \
-H "Authorization: Bearer rsk_your_key" \
-F "image=@receipt.jpg"
curl -X POST https://cudofkdbcfhkdqxxxeje.supabase.co/functions/v1/extract \
-H "Authorization: Bearer rsk_your_key" \
-H "Content-Type: application/json" \
-d '{
"imageBase64": "/9j/4AAQ...",
"mimeType": "image/jpeg"
}'
curl -X POST https://cudofkdbcfhkdqxxxeje.supabase.co/functions/v1/extract \
-H "Authorization: Bearer rsk_your_key" \
-H "Content-Type: application/json" \
-d '{ "imageUrl": "https://example.com/receipt.jpg" }'
| Field | Type | Required | Description |
|---|---|---|---|
image | File | multipart | Receipt image file (JPEG, PNG, or WebP) |
imageBase64 | string | json | Base64-encoded image data |
mimeType | string | with base64 | image/jpeg, image/png, or image/webp |
imageUrl | string | json | HTTPS URL to a receipt image |
Constraints: Max 15 MB. Images only (no PDF). Provide exactly one of image, imageBase64, or imageUrl.
{
"success": true,
"data": {
"upload_id": "uuid",
"extraction_id": "uuid",
"campaign_id": "uuid",
"campaign_name": "My Campaign",
"provider_id": "gemini",
"model_id": "gemini-2.5-flash",
"latency_ms": 7500,
"vision_ms": 6200,
"normalize_ms": 120,
"extraction": {
// ... see Extraction Schema below
}
}
}
{
"success": false,
"error": {
"code": "invalid_image",
"message": "PDF files are not accepted. Upload a photo."
}
}
| Code | HTTP | Description |
|---|---|---|
unauthorized | 401 | Missing, invalid, expired, or revoked API key |
invalid_image | 400 | Not a valid JPEG/PNG/WebP, or file is a PDF |
validation_error | 400 | Missing required fields or bad request body |
unsupported_media | 415 | Content-Type is not multipart or JSON |
extraction_failed | 502 | Vision AI provider error or timeout |
storage_error | 500 | Failed to store image in Supabase Storage |
db_error | 500 | Failed to persist extraction to database |
The extraction object contains all data extracted from the receipt. All fields are nullable — only fields visible on the receipt will have values.
| Field | Type | Description |
|---|---|---|
merchant_name | string | Store or business name |
merchant_address | string | Full address as printed |
merchant_phone | string | Phone number(s) |
merchant_fax | string | Fax number |
merchant_email | string | Email address |
merchant_website | string | Website URL |
merchant_vat_number | string | VAT / tax registration number |
merchant_registration_number | string | Company registration number |
merchant_liquor_license | string | Liquor license number |
store_branch | string | Branch or location name |
store_number | string | Store/shop number |
| Field | Type | Description |
|---|---|---|
purchase_date | string | Date as YYYY-MM-DD |
purchase_time | string | Time as HH:MM or HH:MM:SS (24h) |
currency | string | ISO code (NAD, ZAR, USD, etc.) |
receipt_type | string | "tax_invoice", "receipt", "credit_note" |
receipt_number | string | Receipt or slip number |
invoice_number | string | Invoice number |
transaction_id | string | Transaction reference |
slip_number | string | Slip number |
| Field | Type | Description |
|---|---|---|
cashier_name | string | Cashier / operator name |
cashier_number | string | Cashier ID |
pos_terminal | string | POS / till number |
register_number | string | Register number |
| Field | Type | Description |
|---|---|---|
subtotal | number | Amount before tax |
tax | number | Total VAT / tax amount |
tax_rate | number | Primary VAT % (e.g. 15) |
total | number | Final total |
total_items | number | Number of line items |
total_quantity | number | Total quantity of all items |
total_savings | number | Total discount/promo savings |
rounding | number | Cash rounding amount |
change_due | number | Change given back |
amount_tendered | number | Amount paid |
non_taxable_total | number | Zero-rated items total |
payment_method_hint | string | "card", "cash", "eft", etc. |
tax_breakdown | array | Per-rate tax rows: { rate_percent, tax_amount, gross_amount, net_amount } |
| Field | Type | Description |
|---|---|---|
loyalty_card_number | string | Loyalty / rewards card number |
loyalty_points | string | Points earned or balance |
loyalty_program_name | string | Program name (e.g. "SPAR Rewards") |
card_type | string | Card brand (FNB, Visa, etc.) |
card_last_four | string | Last 4 digits of card |
Array of product lines extracted from the receipt.
| Field | Type | Description |
|---|---|---|
name | string | Product name |
quantity | number | Units purchased |
unit_price | number | Price per unit |
line_total | number | Total for this line |
discount | number | Discount amount on this item |
vat_amount | number | Per-item VAT if shown |
tax_indicator | string | Tax code ("A" taxable, "*" zero-rated) |
barcode | string | EAN/UPC barcode number |
sku | string | Internal product code |
unit_of_measure | string | "each", "kg", "ltr", etc. |
package_size | string | Packaging as printed ("500ML", "1KG", "72'S") |
raw_text | string | Complete raw text of the line |
| Field | Type | Description |
|---|---|---|
warnings | string[] | Notes about image quality or ambiguity |
raw_footer_text | string | Footer messages, return policies |
barcode_at_bottom | string | Barcode number at bottom of receipt |
Included in the extraction as normalization_meta:
| Field | Type | Description |
|---|---|---|
merchant_alias_id | string | Matched alias ID (if normalized) |
merchant_display_name | string | Canonical merchant name after alias lookup |
needs_review | boolean | Flagged for human review |
review_reasons | string[] | Why it was flagged |
Each API key is scoped to a campaign. Campaigns can customize:
The system improves over time through two alias tables:
receipt_scanner_api_merchant_aliases) — Map variations like "Pick n Pay ZA" to canonical "Pick n Pay"receipt_scanner_api_product_aliases) — Map products to tags (e.g. raw pattern "nescafe" → tags ["nescafe_family"])Add aliases via Supabase dashboard or direct SQL. They apply globally or per-campaign.
const form = new FormData();
form.append('image', fileInput.files[0]);
const res = await fetch('https://cudofkdbcfhkdqxxxeje.supabase.co/functions/v1/extract', {
method: 'POST',
headers: { 'Authorization': 'Bearer rsk_your_key' },
body: form,
});
const { data } = await res.json();
console.log(data.extraction.merchant_name);
console.log(data.extraction.total);
console.log(data.extraction.line_items);
import requests
with open('receipt.jpg', 'rb') as f:
r = requests.post(
'https://cudofkdbcfhkdqxxxeje.supabase.co/functions/v1/extract',
headers={'Authorization': 'Bearer rsk_your_key'},
files={'image': f}
)
data = r.json()['data']
print(data['extraction']['merchant_name'])
print(data['extraction']['total'])
curl -X POST https://cudofkdbcfhkdqxxxeje.supabase.co/functions/v1/extract \
-H "Authorization: Bearer rsk_your_key" \
-F "image=@receipt.jpg"
receipt-scanner-apireceipt_scanner_api_extractions| Table | Purpose |
|---|---|
receipt_scanner_api_campaigns | Campaign config, rules, provider overrides |
receipt_scanner_api_service_keys | Hashed API keys scoped to campaigns |
receipt_scanner_api_uploads | Image upload metadata, storage paths, status |
receipt_scanner_api_extractions | Raw + normalized extraction JSON, provider, timings |
receipt_scanner_api_merchant_aliases | Merchant name normalization mappings |
receipt_scanner_api_product_aliases | Product tagging rules |
receipt_scanner_api_async_jobs | Async extraction jobs (future) |