Alya Books

    Developer docs

    REST API, webhooks, MCP server and CLI for UAE e-invoicing

    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": { } }
    
    HTTPcodeWhen
    400BAD_REQUESTMalformed JSON, invalid query parameter, nothing to update
    400E_VALIDATIONStructural 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[])
    401UNAUTHORIZEDMissing, malformed, unknown, revoked or expired key
    403FORBIDDENKey lacks the scope (for example periods:manage to reopen a VAT return), or X-Organization-Id is not a managed client
    404NOT_FOUNDRoute or object not found in this organization
    405METHOD_NOT_ALLOWEDAllow header lists the methods
    409CONFLICTDuplicate SKU, deleting an issued invoice, submission already in progress, accepting twice
    409period_lockedThe document is dated in a locked period (filed VAT return or lock date); extra has lockSource, periodStart, periodEnd, firstOpenDate
    409lock_date_covers_periodReopening a VAT return that the lock date for everyone covers
    409fiscal_settings_conflict_locked_periodsChanging the VAT period settings would cut through a filed return
    413PAYLOAD_TOO_LARGEImport over 20 MB
    422E_VALIDATIONIncoming import recorded but failed validation (extra carries the import)
    429RATE_LIMITEDOver 600 requests per minute; Retry-After header
    501NOT_IMPLEMENTEDFeature not available yet
    502 / 503SERVICE_UNAVAILABLEASP 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)
    500INTERNAL_SERVER_ERRORUnexpected; 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"
    }
    
    • path is the field as you sent it (items[0].taxRate, buyer.trn, precedingInvoice.number); field is the internal name, kept for compatibility. Input checks that run before the rules (a 14-digit TRN, a missing description) answer 400 with field, path and scope at the top level of the envelope.
    • scope says where the fix is: document in the request, organization under Settings → Company (seller TRN, address, bank account, licence).
    • explanation and fix are 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.
    • docsUrl is 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, else APP_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

    RuleMessageFix
    BT-31 / BT-35 / BT-37 / BT-40Seller TRN, street, city or country missingComplete the organization profile in the app
    BT-44Buyer name is requiredProvide buyer.name or buyer.id
    BT-48Buyer TRN must be 15 digitsCorrect buyer.trn, or omit it for unregistered buyers (warning only)
    BT-25Preceding invoice reference requiredCredit and debit notes need precedingInvoice
    BT-129 / BT-146Quantity must be > 0, price cannot be negativeFix the line
    BT-152UAE standard VAT rate must be 5 %Use taxRate: 5 or another category
    BT-106 / BT-110 / BT-112Totals mismatchOnly on PUT with hand-computed totals; let Alya Books compute them
    BT-130Unit code not in UN/ECE Rec 20Warning; 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.