Alya Books

    Developer docs

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

    Changelog

    What changed in the API, the MCP server and the CLI.

    13 October 2026 Brand-neutral identifiers

    New identifiers. New API keys start with sk_test_ or sk_live_. Webhook deliveries carry X-Webhook-Signature, X-Webhook-Event, X-Webhook-Event-Id, X-Webhook-Delivery and X-Webhook-Attempt, with the user agent Webhook-Delivery/1.0. Create results and ERP message replies name the invoice invoiceId. MCP resources use einvoicing:// URIs and tool results carry _meta: { "einvoicing/environment": … }. OAuth access tokens, refresh tokens, authorization codes and client ids start with oat_, ort_, oac_ and ocl_.

    CLI is published as @alyabooks/cli and runs as alyabooks; settings live in ~/.alyabooks/config.json and the ALYABOOKS_API_KEY, ALYABOOKS_API_URL and ALYABOOKS_ORGANIZATION_ID environment variables.

    Nothing to migrate. Keys, tokens, webhook subscriptions and integrations created earlier keep working on deployments that accept the previous identifiers. Verify signatures with the new header names when you next touch your webhook handler.

    September 2026 v1.0

    Public API v1. Invoices (batch create, list, JSON/PDF/XML download, status with ASP and FTA timeline, validation, submit, send, payments, housekeeping), invoice numbers and series settings, incoming imports with content sub-resources, customers, products, custom fields, webhooks, account endpoints. API keys with scopes and test/live environments, X-Organization-Id for CA firms, rate limiting, request log.

    Webhooks. 24 events, HMAC-SHA256 signatures, retries with back-off, delivery log, test deliveries, automatic pause after repeated failures.

    Custom fields. Field definitions and per-kind templates; values on documents and lines, validated, printed on PDFs and included in webhook payloads.

    MCP server at POST /api/v1/mcp with about 70 tools and 7 resources.

    CLI @alyabooks/cli 1.0.

    Docs. This site, the OpenAPI document at /openapi.json, llms.txt, AGENTS.md and CLAUDE.md for coding agents.

    October 2026 v1.1

    Catalogue depth. Customers gain company/person, legal form, category, defaultPriceListId, contact persons (/customers/{id}/contact-persons) and delivery/billing addresses (/customers/{id}/addresses); Peppol lookup (GET /customers/peppol-lookup, POST /customers/{id}/verify-peppol). Products gain item number, GLN, cost price with margin, inventory tracking and category. New resources: /bundles (with GET /bundles/{id}/lines), /price-lists and GET /products/{id}/price.

    Projects (/projects) with totals, projectId on invoice inputs, ?projectId= list filter, GET /projects/{id}/documents. Webhook project.created.

    Recurring invoices (/recurring-invoices) with schedules, automation, runs, preview, POST /invoices/{id}/make-recurring; daily runner. Webhooks recurring_invoice.generated and recurring_invoice.failed.

    MCP grows to about 115 tools and adds the recurring_schedules resource. CLI adds project, recurring, bundle, price-list, customer persons|addresses|peppol commands.

    October 2026 v1.2

    VAT. Tax rates per organization (/settings/tax-rates) with exemption reasons written into the XML (taxExemptionReasonCode / taxExemptionReason on lines); supplyEmirate on invoices; VAT 201 worksheet (GET /vat/worksheet, JSON or CSV), tax periods (GET /vat/periods) and saved returns (/vat/returns). Rounding is half away from zero everywhere (see Rounding rules).

    Accounting exports. GET /exports/accounting produces Zoho Books, Xero and QuickBooks Online CSV and Tally XML for issued invoices or accepted incoming invoices.

    MCP adds eight VAT tools; CLI adds tax-rate, vat and export accounting.

    November 2026 v1.3

    Accounting connectors. QuickBooks Online and Xero (OAuth) and Odoo (JSON-RPC) on the connector framework, each with a sandbox mode: GET /connectors, POST /connectors/{id}/sync (pull contacts and invoices, push issued invoices once), GET /connectors/{id}/links. Webhook connector.synced. See Accounting connectors.

    Pay-by-link. Payment gateways (Stripe, Telr, PayTabs, Tap, mock) under Settings → Payments; POST /invoices/{id}/payment-link, GET /payment-links, POST /payment-links/{id}/cancel; public pay page at /pay/{token}; gateway confirmations settle the link and record the payment. Webhook payment_link.paid.

    Bank feeds. Lean Technologies, Tarabut and mock connections, statement import (POST /bank/import), transactions with match suggestions (GET /bank/transactions), confirm/unmatch/ignore, optional automatic confirmation. Webhook bank.transaction_matched. See Pay-by-link and bank feeds.

    MCP adds ten integration, payment and bank tools; CLI 1.2 adds connector, pay-link and bank.

    November 2026 v1.4

    Simulated receiving. POST /incoming/simulate (Test mode only) generates supplier invoices for a scenario — standard, mixed_vat, reverse_charge, credit_note, foreign_currency, wrong_buyer, totals_mismatch, duplicate — from a sample supplier or one of your contacts, and receives them through the real Peppol pipeline (validation, duplicate check, notifications, webhooks). GET /incoming/simulate lists scenarios and suppliers.

    Email templates. GET /settings/email-templates, PUT and DELETE /settings/email-templates/{kind}/{locale}: subject and body per document kind in English and Arabic with {{placeholders}}. POST /invoices/{id}/send without subject or message now uses the organization's template.

    Options. GET / PATCH /settings/options: hidden modules, draft number reservation (drafts may carry a temporary DRAFT-… number that becomes the real number on validation), inventory on issue and negative-stock policy (allow, warn, block), duplicate customer numbers, default CC/BCC applied to sends that set none.

    MCP adds simulate_incoming_invoice, list_email_templates, save_email_template, get_options; CLI 1.3 adds import simulate, email-template and options.

    November 2026 v1.5

    Options. GET / PATCH /settings/options adds three fields:

    FieldTypeDefaultMeaning
    allowManualNumbersbooleanfalseWhether people may type document numbers in the app editor. Off: the number field is read-only and new documents take the next number of the series. The API and imports can always supply invoiceNumber.
    showTextBlocksbooleanfalseWhether new invoices in the app editor show salutation, introduction, closing and signature. The subject line always shows. Quotes and letters are not affected.
    terminologyobject{}{ "buyer": { "singular", "plural" }, "seller": { "singular", "plural" } }: the words the app uses for contact types (defaults customer/customers and supplier/suppliers). Lower case, up to 30 characters; null resets. Stored type values stay buyer, seller, both.

    Number series. The app's Document Numbering settings now also list the customer (default C-{n}) and item (default IT-{n}) series.

    November 2026 v1.6

    Terminology for received documents. terminology.incoming on GET / PATCH /settings/options sets what the app calls incoming invoices: { "incoming": { "singular": "bill" } }, one of incoming invoice (default), bill, receipt, purchase invoice; the plural follows. Only app labels change; the /incoming resources and incoming.* webhook events keep their names.

    Behaviour change. A PATCH with terminology now keeps the roles you leave out at their current words (before, they were reset to the defaults). Send "terminology": null to reset everything.

    E-invoice status. Submissions still in flight are now checked in the background, so invoice.delivered, invoice.reported and invoice.rejected fire without anyone polling the status endpoint.

    Incoming invoice content. PATCH /import/incoming/{importId} edits the content of drafts: header, seller / buyer / delivery parties, lineItems (with itemDescription and taxCategory), vatBreakdown, paymentTerms, earlyPaymentDiscounts and paymentMeans (several, with account owner, BIC, bank name and reference). GET …/content now returns parties in camelCase with the same keys, paymentMeans as an array (was one object with meansCode / accountId), paymentTerms.earlyPaymentDiscounts, and the delivery address under delivery. Received XML fills the delivery address, every payment means, BIC, item descriptions and GLN. projectId can be set on incoming invoices at any time and is returned in the summary. MCP update_incoming_invoice and CLI import update cover the same edits.

    Simulation. New scenario with_pdf for POST /incoming/simulate: a valid invoice with the supplier's PDF embedded in the XML.

    October 2026 v1.3

    Paid in advance and rounding. Invoice inputs accept prepaidAmount, roundingAmount, prepaymentInvoice and items[].billingPeriod; responses add payableAmount, and outstanding follows it.

    Locked periods. Filing a VAT return locks its period; lock dates lockDateAll and lockDateNonAdmin and fiscalYearStartMonth in /settings/options. Writes into a locked period return 409 period_locked. New POST /vat/returns/{id}/reopen, GET /vat/check-date, scope periods:manage, webhooks vat_return.filed, vat_return.reopened and lock_date.changed, MCP tools reopen_vat_return and check_period_date. The reopen: true flag on POST /vat/returns now needs periods:manage.

    Errors. Permission errors from the database return 403 (were 500).

    Account. Webhook organization.ownership_transferred. Two-factor login and section access apply to people signing in to the app; API keys are not affected.

    Planned Next

    CRM lead sync, idempotency keys, OAuth for third-party apps.

    October 2026 v1.6

    Deemed supplies have nothing due. An invoice whose transactionTypes include deemed_supply is stored and returned with no dueDate, no paymentTerms and an empty paymentMeans, whatever the input carried, and its paymentStatus is the new value nothing_due: outstanding is 0, project outstandingTotal leaves it out, it is never overdue, invoice.paid is never emitted for it and POST /invoices/{id}/payment-link refuses it. The value is additive; code that switches on paid / unpaid should treat it like paid. paymentStatus filters accept it.

    Rules applied up front. Transaction types a document kind forbids (summary_invoice, deemed_supply, profit_margin on 480 and 81, IBR-157-AE), line VAT categories a kind or type fixes (IBR-122-AE, IBR-116-AE) and document-level allowances on a margin scheme invoice (IBR-114-AE) are still reported by validation through the API; the web editor now prevents them before validation.

    October 2026 v1.7

    ERP intake. POST /erp/{connector}/messages takes what an ERP pushes, a CargoWise UniversalTransaction (bare, in a UniversalInterchange or a SOAP envelope, credit notes with their CreditNoteReason) or one InvoiceInput as JSON, stores it, maps it through the organisation's charge map (GET/PUT /erp/connectors/{type}) and creates and submits the invoice. A resend answers duplicate; failures are kept and can be replayed (GET /erp/messages, GET /erp/messages/{id}, POST /erp/messages/{id}/replay). HTTP Basic authentication with the key as password is accepted. See ERP intake.

    Dry run. POST /invoices/validate maps and validates an InvoiceInput, or an ERP message with ?connector=cargowise, without storing anything: the report, mapping notes and a preview.

    Explained errors. Every validation issue carries path (the field as you sent it), scope (document or organization), Alya Books's explanation and fix in English and Arabic, and a public docsUrl; input-check errors carry path and scope too. Invoice webhook payloads add validation and, on invoice.rejected, rejection with the stage and the provider's error. See Errors.

    MCP adds eight ERP tools (dry_run_invoice, dry_run_erp_message, send_erp_message, list_erp_messages, get_erp_message, replay_erp_message, list_erp_connectors, update_erp_connector), marks submitting, sending, replaying and reopening a VAT return as destructive, and names the environment (test or live) in every result's _meta.

    Docs. Every page has Copy as Markdown, View as Markdown, Open in Claude and Open in ChatGPT; each page is plain Markdown at its address plus .md, and the whole site is /docs/llms-full.txt.

    October 2026 v1.8

    MCP over OAuth. claude.ai, ChatGPT and other MCP clients can connect as custom connectors with a sign-in instead of an API key: protected resource and authorization server metadata under the API base, dynamic client registration, authorization code with PKCE, rotating refresh tokens, revocation. The user approves the organisation, test or live and the scopes in the Alya Books app; connections are listed and revoked under API access → API keys → Connected apps. Access tokens work on /mcp only. See MCP server.

    Charge maps merge. PUT /erp/connectors/{type} takes mode: "merge" with removeChargeCodes / removeVatCodes; update_erp_connector always merges; the audit log keeps the previous maps.

    October 2026 v1.9

    Invoice PDFs without a PDF service. GET /invoices/{id}?format=pdf, download_invoice and email attachments return the PDF of invoices, credit and debit notes and proformas on every environment; Alya Books draws them with the same generator as the app.

    Download links. GET /invoices/{id}/download-link?format=pdf|xml|html stores the file privately and returns a signed url that works for 15 minutes without an API key. download_invoice returns a PDF this way by default (delivery: "inline" for base64).

    Draft buyer details. A customer's TRN or name change now reaches its draft and validated invoices.

    October 2026 v1.10

    Document designs. GET /design-templates lists the organisation's PDF designs with their layout: standard, or logistics with a shipment panel (job number, house bill, references, custom fields shown on PDF). Invoices take designTemplateId on create and through PATCH /invoices/{id}; ERP connectors take designTemplateId so their invoices use it. MCP: list_design_templates, and designTemplateId on update_invoice_housekeeping and update_erp_connector.

    Invoice PDF. Prints the buyer's address and trade licence under Bill To, the design's accent colour and the company logo (PNG or JPEG), and custom fields flagged "show on PDF".

    October 2026 v1.11

    CargoWise envelopes. POST /erp/cargowise/messages accepts any Content-Type and unwraps the Universal XML from SOAP (elements, escaped text or base64 gzip stream), JSON fields, base64, gzip and form posts. Messages store and return the sender's messageId and the envelope they arrived in; the dry run (POST /invoices/validate?connector=cargowise) unwraps the same way.

    Security. Bank matching and payment links refuse callers who are not signed in; connector credentials are no longer readable by organisation members; scheduled jobs refuse every call when their secret is not configured.

    October 2026 Docs

    CargoWise integration kit. New pages for integrators: CargoWise integration kit, Testing a CargoWise integration, CargoWise field mapping (also as CSV), Replies to the ERP and Status updates back to the ERP, with a charge-code template to download. Background jobs now run on a schedule: FTA status checks and webhook retries every 5 minutes, the Peppol fetch every 15 minutes, daily jobs at 02:00 and 18:45 UAE time.