Alya Books

    Developer docs

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

    Customers

    Manage the contacts you invoice and receive from.

    Customers are contacts of the organization. The same records serve as buyers on outgoing invoices and as suppliers on incoming ones (type: buyer, seller, both).

    The app shows these types with the organization's own words (default Customer and Supplier; for example Client and Vendor). The words are the terminology option of GET / PATCH /settings/options; the stored and accepted type values never change:

    curl -X PATCH "$BASE/settings/options" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
      -d '{ "terminology": { "buyer": { "singular": "client", "plural": "clients" }, "seller": { "singular": "vendor", "plural": "vendors" } } }'
    

    Words are stored in lower case, up to 30 characters each; a role you leave out keeps its current words, and "terminology": null resets everything. The same option also names received supplier documents in the app: "incoming": { "singular": "bill" } (one of incoming invoice, bill, receipt, purchase invoice).

    Fields

    FieldNotes
    name, nameAr, tradingNameLegal name (BT-44), Arabic name for bilingual PDFs, trading name
    typebuyer (default), seller, both
    trn15-digit Tax Registration Number (BT-48); validated
    peppolId, peppolSchemeIdPeppol participant id, 0235:<TIN>, where the TIN is the first 10 digits of the TRN; peppolId holds the 10-digit TIN without the prefix and peppolSchemeId is 0235
    customerNumberYour reference; generateNumber: true allocates the next number of the customer series
    email, contactName, phone, websiteContact details; email is the default recipient when sending; if it is empty, the contact person with receivesInvoices (primary first) is used
    addressstreet, additional, city, emirate, postalCode, country (ISO 3166-1 alpha-2, default AE)
    paymentTermsDays, defaultCurrency, notes, isActiveDefaults applied in the editor
    isCompany, legalForm, firstName, lastNameCompany (default) with legal form, or natural person
    categoryFree-text group, e.g. wholesale
    defaultPriceListIdPrice list applied to this customer (see Products)
    peppolVerifiedAtSet by POST /customers/{id}/verify-peppol when the SML confirms the registration

    Routes

    curl "$BASE/customers?keyword=buyer&type=buyer&perPage=50" -H "X-API-KEY: $KEY"
    curl -X POST "$BASE/customers" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
      -d '{ "name": "Buyer LLC", "trn": "100000000000011", "email": "ap@buyer.ae", "address": { "city": "Dubai", "country": "AE" }, "generateNumber": true }'
    curl -X PATCH "$BASE/customers/{id}" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" -d '{ "paymentTermsDays": 45 }'
    curl -X DELETE "$BASE/customers/{id}" -H "X-API-KEY: $KEY"
    

    Changing trn or name updates the contact's draft and validated invoices; a value set differently on one invoice is kept, and submitted invoices never change.

    DELETE removes a contact without invoices; a contact that has invoices is deactivated instead (deactivated: true in the response) so history stays intact. GET /customers/next-number previews the next customer number and GET /customers/verify-number?value= checks one.

    POST /customers/import creates up to 500 contacts in one call and returns a per-element result (201 when all succeed, 207 otherwise).

    Inline buyers on invoices

    When you create an invoice with a buyer object instead of buyer.id, Alya Books matches an existing contact by TRN, then by exact name, and otherwise creates one from the inline data. The customer.created webhook fires in that case as well.

    Contact persons and addresses

    curl -X POST "$BASE/customers/{id}/contact-persons" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
      -d '{ "salutation": "Ms", "firstName": "Amal", "lastName": "Hassan", "position": "Finance manager", "email": "amal@buyer.ae", "isPrimary": true }'
    curl -X POST "$BASE/customers/{id}/addresses" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
      -d '{ "kind": "delivery", "label": "Warehouse", "street": "Al Quoz 3", "city": "Dubai", "emirate": "Dubai", "isDefault": true }'
    

    GET, PATCH and DELETE on /customers/{id}/contact-persons/{personId} and /customers/{id}/addresses/{addressId} complete the set. One person per contact is isPrimary; one address per kind (delivery, billing, other) is isDefault. Recurring invoices reference them by contactPersonId (email recipient) and deliveryAddressId (BT-70 to BT-80).

    Peppol lookup

    GET /customers/peppol-lookup?participantId=0235:1000000000 (a bare 15-digit TRN is accepted and converted to its TIN) validates the format and, when DNS is available, checks the Peppol SML for the participant. The response carries valid, registered (true, false, or null when the check could not run), checked (sml, smk, format-only) and a message. POST /customers/{id}/verify-peppol runs the same check for a customer and stores peppolVerifiedAt on success. In mock ASP mode every well-formed id is reported as registered.