Upload a receipt or invoice image and get a structured prefill payload ready to feed into Create Expense.
POST /expenses once the user confirms — typically with vat = "mix" + amount_vat_manual for receipts flagged as multi-rate.
Content-Type: multipart/form-data
POST /expenses once the user confirms.
id — CzUid of an existing supplier matched by CUI/name, or null for a new auto-created onename, cui — best-effort values from the receiptmatchedExisting — true when an existing supplier was found{ id, name }. Both may be null when no match is found.YYYY-MM-DD. Falls back to today if unreadable.YYYY-MM-DD, or null for receipts paid at the point of sale (bon fiscal). When null, the form should auto-mark the expense as paid with paid_date = date and payment_type derived from paymentMethod (or 1 = Cash as fallback).with_vat = false.vatMode = "mix", this is informational only — use amount_vat_manual instead.vatMode = "mix", send this back as amount_vat_manual when posting the expense."flat" (single rate, send vat = <number>) or "mix" (two or more non-zero rate tranches, send vat = "mix" + amount_vat_manual = vatAmount).amount + vatAmount on the mix path.true when only the gross total was printed (typical bon fiscal). On mix mode this is false because amount is the explicit subtotal.null. Each entry: { rate, net, gross, vatAmount } — any of net / gross may be null.On vatMode = "mix", send this array back via vat_breakdown when posting so reports keep accurate per-rate totals."cash", "card", "transfer", "other", or null (typical for factură furnizor printed before payment). Map to payment_type when posting:cash → 1 (Cash, “Numerar prin bon fiscal”)card → 4 (Card)transfer → 3 (Bank transfer / Ordin de plată)other / null → caller decidesreference in the create payload).null.name, quantity, unit_price (NET), vat_rate. May be absent depending on document quality and structure — clients that ignore this field still get correct totals via the aggregate fields."Furnizor nou" — supplier auto-created"Mai multe cote TVA" — multi-rate detected, switch UI to mix mode"Liniile au fost ignorate ..." — items omitted; rely on the aggregate fieldsamount_wvat = 147.53, amount_vat = 24.15, amount_total = 171.68 exactly.
file_missing — no image part in the multipart bodyinvalid_file_type — unsupported extension (must be jpg/jpeg/png/webp)invalid_mime_type — content sniff didn’t match an accepted image MIMEfile_too_large — file exceeds 10 MBocr_unavailable — extraction failed; safe to retryocr_not_configured — OCR is not enabled on this deploymentUse your API key (sk_live_xxx or sk_test_xxx)
Receipt image (JPEG / PNG / WebP, ≤ 10 MB).
Extracted prefill payload
Normalized prefill returned by POST /expenses/ocr-extract. Map to a Create Expense body — see the OCR endpoint guide for the full translation table.
Opaque 15-min token for the staged image; pass through to attachments.
Net subtotal (excluding VAT).
Dominant VAT rate.
Total VAT across all rate tranches.
"flat" = single rate; send vat = <number> on POST.
"mix" = two or more non-zero rate tranches; send vat = "mix"
+ amount_vat_manual = vatAmount on POST.
flat, mix Gross total printed on the receipt.
Inferred payment method. Map to payment_type on POST:
cash→1, card→4, transfer→3, other/null→caller decides.
cash, card, transfer, other, null Optional. May be absent depending on document quality and structure. Clients that ignore this field still get correct totals via the aggregate fields.
Pre-localized Romanian strings safe to surface in the form alert.