One shape on every route: type, code, message, param, doc_url, request_id and errors.
← Back to the API documentation
Your first invoice in 6 steps
- Every 4xx and 5xx returns { "error": { type, code, message, param?, doc_url, request_id, errors? } }.
- Branch on type to decide whether a retry makes sense, and map code into your own system.
- param points at the offending field, e.g. lines.0.vat_rate; errors[] appears when there are several.
- Log request_id on every error — it lets us find the exact request in our logs.
What the 4invoices API is
json
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "Datele trimise nu sunt valide.",
"param": "lines.0.vat_rate",
"doc_url": "https://4invoices.net/ro/api-dezvoltatori#errors",
"request_id": "req_8a893f2f33d4472da8d6e144",
"errors": [
{ "param": "lines.0.vat_rate", "message": "VAT rate must be a percent (21), not a fraction", "type": "value_error" }
]
}
}https://api.4invoices.net/v1 · https://api.4invoices.net/v1/openapi.json
Errors
| Status | Type | Code |
|---|---|---|
| 401 | authentication_error | missing_bearer_token |
| 401 | authentication_error | unauthorized |
| 403 | permission_error | forbidden |
| 404 | not_found_error | not_found |
| 409 | conflict_error | idempotency_key_reuse |
| 409 | conflict_error | idempotency_in_progress |
| 422 | invalid_request_error | validation_failed |
| 422 | invalid_request_error | invalid_json_number |
| 502 | upstream_error | upstream_error |
| 503 | service_unavailable_error | service_unavailable |
Common mistakes
- rate_limit_error and the two upstream types are retryable. authentication_error, permission_error and invalid_request_error are not fixed by retrying.
- A 404 is also returned for an id that belongs to another tenant: we never confirm that someone else's data exists.
- 409 idempotency_key_reuse means you reused a key with a different body. Do not force it: check what was already issued.
- The doc_url in every error points straight at the errors section of this documentation.
- Messages are in Romanian because the API serves a Romanian fiscal flow; do not parse message, branch on code.
Developer questions and answers
Can I rely on code values across versions?
Yes, code is stable and exists precisely for that. message is human text and may be rephrased.
What should I do on a 502 or 503?
Retry with exponential backoff. Those are upstream or temporary-availability errors, not problems with your request.
Why 422 and not 400 for invalid data?
422 marks well-formed but semantically invalid JSON — for example vat_rate as a fraction. 400 is reserved for a malformed request.