Errors
The Integration API error model (RFC 7807 problem+json) and the full catalog of status codes with their meaning and fix.
When a request fails, the Integration API returns a standard HTTP status code and
an RFC 7807 application/problem+json
body:
{
"type": "https://integration.fatorly.com/errors/validation-failed",
"title": "Validation Failed",
"status": 422,
"detail": "2 business-rule violations",
"instance": "/v1/invoices",
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
"errors": [
{ "field": "lines[0].vatRate", "message": "VAT rate not permitted for category S" }
]
}
| Field | Meaning |
|---|---|
type | Stable machine-readable identifier. Branch on this (or on status) — never on title/detail text, which may change. |
title | Short human-readable summary of the error class. |
status | The HTTP status code, repeated in the body. |
detail | What went wrong in this specific case (optional). |
instance | The request path that produced the error (optional). |
traceId | Correlation id — include it when contacting support (optional). |
errors | Field-level validation errors, each with field and message (optional). |
Error catalog
All type identifiers live under https://integration.fatorly.com/errors/:
| Status | type suffix | Meaning | How to fix |
|---|---|---|---|
| 400 Bad Request | bad-request | Malformed/unparseable JSON, a field that fails validation, or the required Idempotency-Key header is missing or too long. | Check detail and errors[]. Add an Idempotency-Key header and correct any invalid fields. |
| 401 Unauthorized | unauthorized | The X-Api-Key header is missing or the key is invalid or revoked. | Send a valid key in X-Api-Key. If it was revoked, create a new key. |
| 402 Quota Exceeded | quota-exceeded | Your monthly document quota has been reached. | Wait for the quota to reset or upgrade your plan. |
| 403 Forbidden | forbidden | The key is valid but lacks the scope the endpoint requires (e.g. invoices:write). | Adjust the key's scopes in Settings → API Keys, or use a key that has the scope. |
| 404 Not Found | not-found | The endpoint or referenced resource doesn't exist. | Verify the URL, the resource id, and that the key's company owns it. |
| 409 Conflict | conflict | An Idempotency-Key was reused with a different body, or the document is in a state that forbids the operation (e.g. cancelling a submitted invoice). | Use a fresh key for a new request, or resolve the document-state conflict. |
| 422 Validation Failed | validation-failed | The document failed PINT-AE schematron validation. | Read errors[] for the failing rules and correct the invoice data (for example a missing exemptionReasonCode on an exempt line). |
| 429 Too Many Requests | rate-limited | Rate limit exceeded (default 100 requests per 10 seconds per company). | Wait for the number of seconds in the Retry-After header, then retry. |
| 500 Internal Server Error | internal-error | An unexpected platform fault. | Retry with backoff; report the traceId if it persists. |
| 502 Upstream Error | upstream-error | The gateway could not get a valid response from an upstream service — your request itself was well-formed. | Retry with backoff. |
Note
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.
Note
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— always0on a rejected request.
Validation and quota
Idempotency-Keyis mandatory on everyPOST(except…/validate); omitting it is the most common cause of 400. See Idempotency.- An
exemptionReasonCodeis required on any line whosetaxCategoryCodeisE; 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 asubmissionErrorwith the reason (a PINT-AE rule failure or a Peppol delivery error). - Or poll a single document with
GET /invoices/{id}— when its status isDeliveryFailed, the response includes the samesubmissionError.
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.
Note
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
typeURI (orstatus), never ontitle/detailtext. - Retry transient failures (429, 500, 502, network errors,
timeouts) with backoff, and reuse the same
Idempotency-Keyon 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
traceIdof any unexpected 500/502 — support can use it to find the exact request in the platform logs.
Related
- Authentication — fixing 401s and 403s.
- Idempotency — fixing missing-key 400s and conflict 409s.