Invoice status
Every status code an invoice can carry, and the endpoints for reading one invoice's current state. The full list is published below and served by an unauthenticated endpoint, so a code you have not seen before never has to reach your users as an unrecognised state.
An invoice carries a status trail — an append-only array of { code, message, created_at } rows. Rows are never replaced, so the last row is the invoice's current state. Every code below can appear in that array; nothing outside this list is emitted.
Rather than matching on codes directly, switch on category and stop polling when terminal is true — the status endpoint returns both, so a new code added to a phase you already handle needs no change on your side. A code your integration does not recognise comes back as category: "unknown", never as a missing field.
What changed in catalogue 1.1.0
RECEIVED_SUCCESSFULLYis new. Every received invoice that passes validation for your entity gets it: the invoice is stored, ready to read and download. With an accounting system connected,SENT_TO_<ERP>follows once the invoice is synced there.WAITING_FOR_ERP_CONNECTIONis no longer written. It is deprecated in favour ofRECEIVED_SUCCESSFULLYand re-categorised fromblockedtosuccess. Invoices received before the change still carry it, so keep recognising it and treat the two the same.SENT_TO_<ERP>codes are unchanged; they are now described as the invoice being successfully synced to that system.
If your integration checks for WAITING_FOR_ERP_CONNECTION by code, add RECEIVED_SUCCESSFULLY beside it, or switch on category instead.
Work is still in flight. Keep polling; a further status row is expected.
The step completed successfully.
The step failed. See the row's message (and errors, when present).
Nothing is wrong with the document - it is parked waiting on configuration or a human decision, and will move on once that is resolved.
Poll one invoice
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
https://dev-api.taxstar.app/einv/oauth/invoices/{invoice_id}/status
{
"invoice_id": "68f0aabbccddeeff00112233",
"invoice_number": "INV-1042",
"direction": "sent",
"status": "VALIDATION_FAILED",
"message": "Validation failed: the invoice did not pass the re-check made just before sending, so it was not sent. ...",
"created_at": "2026-09-11T08:14:02.911+00:00",
"category": "failed",
"phase": "validation",
"terminal": true,
"description": "The invoice failed validation and was not sent. ...",
"final_status": "failed",
"status_count": 3,
"errors": [{ "rule": "ibr-173-ae", "message": "..." }]
}49 codes · catalogue v1.1.0
Queued
PROCESSINGin progress | The invoice passed validation and was queued for processing. This is the status returned by POST /oauth/invoices and by a PATCH that re-queues an invoice; one that fails validation is answered 422 instead and never gets a status. | sent · received |
WEBHOOK_RECEIVEDin progress | The processing pipeline picked the queued invoice up and started work on it. | sent · received |
Validation
VALIDATION_IN_PROGRESSin progress | The invoice is being checked against the PINT AE rules. | sent · received |
VALIDATION_SUCCEEDEDsuccess | The invoice passed validation and moves on to XML conversion. | sent · received |
VALIDATION_FAILEDfailedterminal | The invoice failed validation and was not sent. The status row carries an 'errors' array with the failing rules. Fix the data and PATCH the invoice to re-queue it. A sent invoice is validated twice: when it is submitted (a failure there is a 422 on the request and no invoice is created) and again just before sending. This status comes from that second check, so it usually means something changed after the invoice was accepted, typically the entity's details or the exchange rate. | sent · received |
XML conversion
XML_CONVERTEDsuccess | The invoice was converted to UBL XML, ready for dispatch. | sent |
XML_CONVERTED_FAILEDfailedterminal | UBL XML could not be produced from the invoice data. Fix the data and PATCH the invoice to re-queue it. | sent |
XML_VALIDATEDsuccess | The generated UBL XML passed schema validation. | sent |
XML_VALIDATED_FAILEDfailedterminal | The generated UBL XML failed schema validation. | sent |
Dispatch to Peppol
SENT_TO_PEPPOLsuccessterminal | The invoice was accepted by the Peppol access point for delivery. This is the terminal success state of the send flow: the invoice becomes immutable and a PATCH returns 409. | sent · received |
SENT_TO_PEPPOL_FAILEDfailedterminal | The access point rejected the invoice at dispatch. The invoice is still editable - PATCH it to re-queue. | sent · received |
SENT_TO_BILLBERRYsuccessterminallegacy | Legacy spelling of SENT_TO_PEPPOL, written before the gateway was renamed. Treat it exactly as SENT_TO_PEPPOL. Treat as SENT_TO_PEPPOL. | sent · received |
SENT_TO_BILLBERRY_FAILEDfailedterminallegacy | Legacy spelling of SENT_TO_PEPPOL_FAILED. Treat it exactly as SENT_TO_PEPPOL_FAILED. Treat as SENT_TO_PEPPOL_FAILED. | sent · received |
Peppol delivery
DELIVERED_BY_PEPPOLsuccessterminalreserved | The receiving access point acknowledged the document. Reported asynchronously after SENT_TO_PEPPOL. Published ahead of its producer - recognise it now, do not expect it yet. | sent |
PEPPOL_DELIVERY_FAILEDfailedterminalreserved | The receiving access point rejected the document after it had been accepted for delivery. Published ahead of its producer - recognise it now, do not expect it yet. | sent |
Arrival
RECEIVED_BY_PEPPOLin progress | An invoice addressed to one of your entities arrived over the Peppol network and was stored. This is the first row on every received invoice. | received |
RECEIVED_SUCCESSFULLYsuccess | The invoice was received successfully: it passed validation for one of your entities and is stored, ready to read and download. If the entity has an ERP connected, the invoice is then synced into it (SENT_TO_<ERP>). | received |
WAITING_FOR_ERP_CONNECTIONsuccesslegacy | Legacy code for RECEIVED_SUCCESSFULLY, on invoices received for an entity without an ERP before RECEIVED_SUCCESSFULLY was introduced. Treat it exactly as RECEIVED_SUCCESSFULLY. Treat as RECEIVED_SUCCESSFULLY. | received |
RECEIVED_BY_BILLBERRYin progresslegacy | Legacy spelling of RECEIVED_BY_PEPPOL. Treat it exactly as RECEIVED_BY_PEPPOL. Treat as RECEIVED_BY_PEPPOL. | received |
Routing
WAITING_FOR_TAX_CONFIGURATIONblocked | The invoice is compliant, but its VAT treatment has no matching tax code in the receiving entity's ERP profile. Held until the tax code is configured - the document itself needs no change. | received |
WAITING_FOR_MAPPINGblocked | The invoice is compliant, but one or more lines could not be matched to exactly one tax code, or to one product, in the receiving entity's ERP. It is held, not posted, and the status message names each line's reason. Most are resolved by choosing (or creating) the tax code or product; a treatment the ERP cannot represent cannot be resolved by mapping. | received |
MAPPING_ANSWEREDin progress | A document held for mapping was answered, or its ERP's codes and products were asked to be read again. It is queued and re-processed within a minute: it posts, or is held again with the reason. | received |
WAITING_FOR_ERP_RATE_LIMITin progress | The receiving entity's ERP refused a call for its rate limit. Nothing failed: the invoice is retried automatically once the ERP's wait has passed. | received |
WAITING_FOR_APPROVALblocked | The invoice is waiting for a human approval decision. A sent invoice is held before it goes to Peppol when the entity requires approval for sending and the invoice was pushed with bypass_send_approval false; its approvers are emailed, and approving it sends it. | sent · received |
EXCLUDED_FROM_EINVOICINGblockedterminal | The invoice is outside UAE e-invoicing — sent through the API with einv_scope "excluded", or a sale to a private individual, Article 42 financial services or a Tax Group sale found by the platform. It was not validated, sent to Peppol or reported to the FTA. A person can reopen it from the dashboard; it is then validated and sent like any other invoice. | sent |
INVOICE_OPERATION_DISABLEDblockedterminal | Invoice operations are switched off for the entity, so the invoice was deliberately not processed. Neither a success nor a failure. | sent · received |
DATA_MISSINGfailedterminal | The received document is missing data required to route it into an ERP. | received |
DRAFT_BLOCKEDfailedterminal | The invoice was left as a draft and not processed further. | received |
APPROVEDsuccess | The invoice was approved. A sent invoice is re-queued and goes to Peppol; a received one continues into the ERP. | sent · received |
REJECTEDfailedterminal | The invoice was rejected by an approver and was not sent. Fix it and PATCH the invoice with bypass_send_approval false to submit it for approval again; a PATCH without it sends the invoice. | sent · received |
Delivery into your ERP
SENT_TO_XERO_IN_PROGRESSin progress | The received invoice is being synced to Xero. | received |
SENT_TO_XEROsuccessterminal | The received invoice was successfully synced to Xero: it is now a bill there. | received |
SENT_TO_XERO_FAILEDfailedterminal | The received invoice could not be synced to Xero; the row's message carries the ERP's error. | received |
SENT_TO_QUICKBOOKS_IN_PROGRESSin progress | The received invoice is being synced to QuickBooks. | received |
SENT_TO_QUICKBOOKSsuccessterminal | The received invoice was successfully synced to QuickBooks: it is now a bill there. | received |
SENT_TO_QUICKBOOKS_FAILEDfailedterminal | The received invoice could not be synced to QuickBooks; the row's message carries the ERP's error. | received |
SENT_TO_ZOHO_IN_PROGRESSin progress | The received invoice is being synced to Zoho. | received |
SENT_TO_ZOHOsuccessterminal | The received invoice was successfully synced to Zoho: it is now a bill there. | received |
SENT_TO_ZOHO_FAILEDfailedterminal | The received invoice could not be synced to Zoho; the row's message carries the ERP's error. | received |
SENT_TO_NAQOOD_IN_PROGRESSin progress | The received invoice is being synced to Naqood. | received |
SENT_TO_NAQOODsuccessterminal | The received invoice was successfully synced to Naqood: it is now a bill there. | received |
SENT_TO_NAQOOD_FAILEDfailedterminal | The received invoice could not be synced to Naqood; the row's message carries the ERP's error. | received |
SENT_TO_ODOO_IN_PROGRESSin progress | The received invoice is being synced to Odoo. | received |
SENT_TO_ODOOsuccessterminal | The received invoice was successfully synced to Odoo: it is now a bill there. | received |
SENT_TO_ODOO_FAILEDfailedterminal | The received invoice could not be synced to Odoo; the row's message carries the ERP's error. | received |
SENT_TO_WAFEQ_IN_PROGRESSin progress | The received invoice is being synced to Wafeq. | received |
SENT_TO_WAFEQsuccessterminal | The received invoice was successfully synced to Wafeq: it is now a bill there. | received |
SENT_TO_WAFEQ_FAILEDfailedterminal | The received invoice could not be synced to Wafeq; the row's message carries the ERP's error. | received |
/oauth/invoices/{invoice_id}/statusAccess tokenGet current status (sent)
Return ONLY the current status of a sent invoice — the last row of its status trail, plus how that code should be treated. `status` is the raw code; `category` collapses it into in_progress / success / failed / blocked so you do not have to hard-code which codes mean what; `terminal` tells you when to stop polling. A VALIDATION_FAILED response also carries the failing rules in `errors`.
Use this, not the full invoice endpoint, to follow an invoice. It projects away the invoice data and the status history, so it stays cheap to poll. Stop when the response has terminal: true.
Path parameters
invoice_id | Invoice id returned by POST /oauth/invoices (also accepted at /oauth/invoices/sent/{invoice_id}/status). |
/oauth/invoices/received/{invoice_id}/statusAccess tokenGet current status (received)
Return ONLY the current status of a received invoice, in the same shape as the sent-invoice status endpoint, plus sender_registry_code and receiver_registry_code. RECEIVED_SUCCESSFULLY means the invoice was received successfully: it is complete and readable, and nothing is wrong. For an entity with no connected accounting system it is where the invoice stays; with one connected, SENT_TO_<ERP> follows once the invoice is synced to it. Invoices received before RECEIVED_SUCCESSFULLY was introduced carry the legacy WAITING_FOR_ERP_CONNECTION instead; treat it the same. An example is under Received invoices on the Invoices page.
Path parameters
invoice_id | The numeric `id` from the received-invoices list, e.g. 15231. |
/oauth/invoices/status-codesPublicList all status codes
The complete published catalogue of invoice status codes, machine-readable. Each entry carries `code`, `phase`, `category`, `terminal`, `applies_to` and a description; `deprecated` entries are legacy wire values still present on historical documents (with `superseded_by` naming the current code), and `reserved` entries are published ahead of their producer. No authentication required — cache the response and compare `version` to detect a change.
Query parameters
direction | Restrict to codes that appear on `sent` or on `received` invoices. Defaults to all. |