ZIMRA Fiscalisation REST API — Fiscalise From Any System
Overview. One endpoint fiscalises anything: in-house systems, Dynamics 365, SAP Business One, Xero via Zapier, WooCommerce, mobile apps. POST the invoice JSON; get back the QR URL, verification code and fiscal numbers in the same response.
Authenticate
Header X-Api-Key: tf_… on every call. Your key is in Portal → Settings & Branding.
POST /api/invoices
Send the canonical invoice. Field names matter — this is the exact shape the API validates:
{
"invoice_no": "INV-001",
"receipt_type": "FiscalInvoice",
"currency": "USD",
"lines_tax_inclusive": true,
"buyer": {"name": "Acme Distributors", "tin": "1010101010"},
"lines": [
{"name": "Cement 32.5N", "hs_code": "25232900", "qty": 10,
"price": 11.55, "total": 115.50, "tax_percent": 15.5, "tax_id": 3}
],
"payments": [{"money_type": "Cash", "amount": 115.00}]
} The buyer object is buyer (not customer), the unit price is price (not unit_price) and the rate is tax_percent (not tax_rate). HS codes are optional — we auto-fill them.
Know What Is Required
A payload that is missing something comes back 422 with a message naming every problem at once, not just the first. The rules:
invoice_no— required, 50 characters maximum.currency— required, exactly 3 letters (USD,ZWG,ZAR…).receipt_type—FiscalInvoice(the default),CreditNoteorDebitNote. Nothing else.lines— a non-empty list. Every line needs anameand atotalor aprice; sendtotalwhenever you can. Any oftotal,price,qty,tax_percentthat is present must be a number.payments— optional. If you send it, it must be a list and each entry needs a numericamount. Leave it out and we settle the whole invoice to Cash.credited_invoice— required whenreceipt_typeisCreditNoteorDebitNote.
Use the Response
You receive id, status, qr_url, verification_code, receipt_global_no, receipt_counter, error_code and attempts — render the QR and verification code on your invoice. Always check status: fiscalised and fiscalised_yellow mean ZIMRA accepted it; error means it did not, and error_code tells you why. Full reference with worked examples: API Documentation.
invoice_no and receipt_type to the same device returns the receipt that was already fiscalised instead of creating a second one — safe to retry after a timeout. A credit note may reuse the invoice number it reverses.status: "error" and a retryable error_code — it is stored, never lost, and you re-submit it with Resend in the portal or POST /portal/receipts/{id}/resend. If you trade in places with no connectivity, ask us about offline batch mode (/api/offline/queue and /api/offline/sync), included on Enterprise and available as an add-on.