Errors
Status codes, error codes and how to handle them.
Every error response has the same shape:
{ "code": "E_VALIDATION", "statusCode": 400, "message": "buyer.trn must be 15 digits", "field": "buyer.trn", "extra": { } }
| HTTP | code | When |
|---|---|---|
| 400 | BAD_REQUEST | Malformed JSON, invalid query parameter, nothing to update |
| 400 | E_VALIDATION | Structural validation of the payload (field names the input) or PINT AE business rules (extra.errors[] with rule, field, message, severity) or custom fields (extra.fields[]) |
| 401 | UNAUTHORIZED | Missing, malformed, unknown, revoked or expired key |
| 403 | FORBIDDEN | Key lacks the scope (for example periods:manage to reopen a VAT return), or X-Organization-Id is not a managed client |
| 404 | NOT_FOUND | Route or object not found in this organization |
| 405 | METHOD_NOT_ALLOWED | Allow header lists the methods |
| 409 | CONFLICT | Duplicate SKU, deleting an issued invoice, submission already in progress, accepting twice |
| 409 | period_locked | The document is dated in a locked period (filed VAT return or lock date); extra has lockSource, periodStart, periodEnd, firstOpenDate |
| 409 | lock_date_covers_period | Reopening a VAT return that the lock date for everyone covers |
| 409 | fiscal_settings_conflict_locked_periods | Changing the VAT period settings would cut through a filed return |
| 413 | PAYLOAD_TOO_LARGE | Import over 20 MB |
| 422 | E_VALIDATION | Incoming import recorded but failed validation (extra carries the import) |
| 429 | RATE_LIMITED | Over 600 requests per minute; Retry-After header |
| 501 | NOT_IMPLEMENTED | Feature not available yet |
| 502 / 503 | SERVICE_UNAVAILABLE | ASP unreachable, email provider failed, PDF of a document other than an invoice, credit or debit note or proforma requested where no PDF service is configured (?format=html still works) |
| 500 | INTERNAL_SERVER_ERROR | Unexpected; include X-Request-Id when reporting it |
Validation errors, explained
Every PINT AE validation issue the API returns (extra.errors[] on a 400, and errors[] / warnings[] on the validation, status, create and dry-run responses) carries more than the rule and a message:
{
"rule": "IBR-190-AE",
"field": "lines[0].tax_rate",
"path": "items[0].taxRate",
"scope": "document",
"severity": "error",
"message": "Line 1: Standard-rated lines carry 5 %",
"explanation": "A line taxed at the standard rate must state the UAE standard rate of 5 %.",
"fix": "Set the line's VAT rate to 5, or change its VAT category.",
"explanationAr": "…",
"fixAr": "…",
"docsUrl": "https://alyabooks.ai/reference/rules/IBR-190-AE.html"
}
pathis the field as you sent it (items[0].taxRate,buyer.trn,precedingInvoice.number);fieldis the internal name, kept for compatibility. Input checks that run before the rules (a 14-digit TRN, a missing description) answer 400 withfield,pathandscopeat the top level of the envelope.scopesays where the fix is:documentin the request,organizationunder Settings → Company (seller TRN, address, bank account, licence).explanationandfixare Alya Books's plain-language text; the Arabic pair is there for finance teams working in Arabic. Business-term codes (BT-…) carry a link to the field catalogue instead of an explanation.docsUrlis public and needs no login, so it can go straight into an ERP job note or a webhook receiver's log. The links are built on the deployment's public site (PUBLIC_SITE_URL, elseAPP_URL); the webhook sender rewrites the links in payloads to the same site before signing.
Batch responses
POST /invoices, /customers/import and /products/import process elements independently. For invoices, a failure turns the whole response into an error whose extra.results[] holds per-element outcomes; created elements are marked success: true. Customer and product imports answer 207 with results[] and never roll back created elements.
Validation rules you will meet
| Rule | Message | Fix |
|---|---|---|
| BT-31 / BT-35 / BT-37 / BT-40 | Seller TRN, street, city or country missing | Complete the organization profile in the app |
| BT-44 | Buyer name is required | Provide buyer.name or buyer.id |
| BT-48 | Buyer TRN must be 15 digits | Correct buyer.trn, or omit it for unregistered buyers (warning only) |
| BT-25 | Preceding invoice reference required | Credit and debit notes need precedingInvoice |
| BT-129 / BT-146 | Quantity must be > 0, price cannot be negative | Fix the line |
| BT-152 | UAE standard VAT rate must be 5 % | Use taxRate: 5 or another category |
| BT-106 / BT-110 / BT-112 | Totals mismatch | Only on PUT with hand-computed totals; let Alya Books compute them |
| BT-130 | Unit code not in UN/ECE Rec 20 | Warning; use EA, HUR, KGM, … |
The PINT AE field reference lists all business terms.
Idempotency
The API has no idempotency keys yet. Use externalId on invoices (GET /invoices?externalId=) and reference on imports to detect repeats before you retry, and reconcile batches with extra.results.