Alya Books

    Developer docs

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

    Status updates back to the ERP

    How the ERP learns what happened to an invoice after Alya Books accepted the message: webhooks or polling, the statuses, rejections, and the XML and PDF to attach to the job.

    The reply to a pushed message says whether Alya Books created the invoice. What happens next (submission to the service provider, reporting to the FTA, a rejection) arrives later, usually within minutes. Alya Books checks the provider every five minutes and reports each change by webhook; your side can also poll.

    The statuses

    invoiceStatusMeaningWebhook event
    validatedCreated and valid, not yet submitted (the connector's submit setting is off, or approval is pending)invoice.created
    submittedHanded to the accredited service providerinvoice.submitted
    deliveredThe buyer's access point accepted itinvoice.delivered
    acceptedReported to the FTAinvoice.reported
    rejectedRefused by the provider, the buyer's access point or the FTAinvoice.rejected

    invoice.reported and invoice.rejected are the two your write-back needs; the others are optional progress.

    Create a subscription once:

    curl -X POST {BASE}/webhooks -H "X-API-KEY: sk_test_…" -H "Content-Type: application/json" \
      -d '{"targetUrl":"https://your-middleware.example/einvoicing","events":["invoice.reported","invoice.rejected","invoice.submitted"]}'
    

    The reply contains the signing secret (whsec_…) once. Each delivery is a signed POST:

    {
      "id": "9b1e…",                          // event id: the same for every subscriber, use it to de-duplicate
      "event": "invoice.rejected",
      "createdAt": "2026-10-13T07:15:00Z",
      "organizationId": "…",
      "data": {
        "id": "ac20fac3-…",                   // invoiceId
        "invoiceNumber": "INV-2027-00412",
        "externalId": "cargowise:DXB:INV:INV-2027-00412",   // match it to the CargoWise transaction
        "invoiceTypeCode": "380",
        "status": "rejected",
        "issueDate": "2026-10-13", "currency": "AED", "total": 17140,
        "buyer": { "id": "…", "name": "…", "trn": "100123456700003" },
        "metadata": { "job": "S00123456", "house_bill": "DXBSHA2701234", "branch": "DXB" },
        "validation": { "validity": true, "errors": [] },
        "rejection": { "stage": "fta", "error": "…", "submissionId": "…", "at": "2026-10-13T07:14:58Z" },
        "isTest": true
      }
    }
    
    • Match on data.externalId (the message key) or data.invoiceNumber (the CargoWise number).
    • On invoice.rejected, data.rejection.stage says who refused it (taxilla for the service provider, buyer, fta) and error why. Show it to the person who posted the invoice; the fix is a corrected document or a credit note.
    • Verify X-Webhook-Signature (HMAC-SHA256 of "<t>.<raw body>") and reject timestamps older than five minutes. See Webhooks for code.
    • Answer 2xx within 10 seconds. Failed deliveries are retried with back-off (checked every five minutes) and stay visible under GET {BASE}/webhooks/{id}/deliveries.

    Polling

    Without a webhook receiver, poll the invoices still in progress:

    GET {BASE}/invoices/{invoiceId}/status
    
    {
      "invoiceId": "ac20fac3-…",
      "invoiceNumber": "INV-2027-00412",
      "invoiceStatus": "accepted",
      "jobStatus": "done",                    // processing | ready | done | failed
      "authority": [
        { "type": "fta", "provider": "taxilla", "mode": "uat", "status": "accepted", "stage": null,
          "referenceNumber": "90d455ab-…", "requestId": "205a32b2-…", "submittedAt": "…", "completedAt": "…", "error": null }
      ],
      "validation": { "validity": true, "errors": [], "warnings": [] }
    }
    

    Poll every few minutes, and stop once jobStatus is done or failed. To find invoices by message key, use GET {BASE}/invoices?externalId=cargowise:DXB:INV:INV-2027-00412.

    The documents to attach to the job

    DocumentRequestNotes
    PINT AE XML as reportedGET {BASE}/invoices/{id}?format=xmlAfter submission this is the exact XML that was sent
    PDFGET {BASE}/invoices/{id}?format=pdfThe same PDF the app downloads and emails, in the invoice's design
    A link instead of the fileGET {BASE}/invoices/{id}/download-link?format=pdf (or xml)A signed URL that works for 15 minutes without a key, for middleware that fetches files separately

    Writing back into CargoWise

    In the first phase your middleware (or a person) attaches the documents and sets the job's e-invoice status from these events. In the next phase Alya Books posts them into CargoWise itself through eAdaptor's inbound interface; see What comes later.