Skip to main content
When a request fails, the Integration API returns a standard HTTP status code and an RFC 7807 application/problem+json body:

Error catalog

All type identifiers live under https://integration.fatorly.com/errors/:
400 vs 422. A 400 means the request itself is malformed — bad JSON, a missing header, or a field that doesn’t validate. A 422 means the request was well-formed but the resulting e-invoice doesn’t pass the UAE PINT-AE rules.
500 vs 502. A 502 means your request was fine but an upstream hop failed — safe to retry with backoff. A 500 is an unexpected fault; if it persists, contact support with the traceId.

Rate limiting

Requests are limited per company. A 429 response carries two headers:
  • Retry-After — seconds to wait before retrying.
  • X-RateLimit-Remaining — always 0 on a rejected request.

Validation and quota

  • Idempotency-Key is mandatory on every POST (except …/validate); omitting it is the most common cause of 400. See Idempotency.
  • An exemptionReasonCode is required on any line whose taxCategoryCode is E; omitting it triggers a validation error.
  • A 402 is about your plan, not your request — the request was otherwise valid. Retrying won’t help until the quota resets.

Delivery failures after submit

POST /invoices/{id}/submit is asynchronous: it returns 202 with status Pending, and the PINT-AE validation and Peppol delivery happen in the background. If either fails, the document’s status becomes DeliveryFailed — a successful 202 on submit therefore does not guarantee delivery.
  • List every failed document with GET /invoices/failed — each item carries a submissionError with the reason (a PINT-AE rule failure or a Peppol delivery error).
  • Or poll a single document with GET /invoices/{id} — when its status is DeliveryFailed, the response includes the same submissionError.
To recover: fix the data with PUT /invoices/{id}, re-check it with POST /invoices/{id}/validate until it returns "valid": true, then submit again with POST /invoices/{id}/submit.
POST /invoices/{id}/validate runs the same checks as the background submission and persists nothing — call it as often as you like while fixing a document. It is the one POST that does not require an Idempotency-Key.

Handling errors in code

  • Branch on the type URI (or status), never on title/detail text.
  • Retry transient failures (429, 500, 502, network errors, timeouts) with backoff, and reuse the same Idempotency-Key on POSTs so you never duplicate a document.
  • Do not blindly retry 400/401/402/403/404/409/422 — these need a fix (correct the payload, the key, its scopes, or your plan), not another attempt.
  • Log the traceId of any unexpected 500/502 — support can use it to find the exact request in the platform logs.