Alya Books

    Developer docs

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

    Pay-by-link and bank feeds

    Create payment links for invoices, receive gateway confirmations, and reconcile bank transactions with automatic match suggestions.

    Payment gateways

    Gateways are configured in the app under Settings → Payments (owners and admins): Stripe, Telr, PayTabs, Tap, or the built-in mock gateway for development. GET /payment-gateways lists them without credentials and returns the supported providers with their credential fields.

    Each gateway has mode = test or live. Test documents can only use test-mode or mock gateways.

    curl -X POST "$BASE/invoices/$INVOICE_ID/payment-link" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
      -d '{ "gatewayId": null, "expiresInDays": 30 }'
    

    Rules enforced by the database function behind it:

    • the invoice must be issued (not draft), not a credit note, and have an outstanding amount;
    • gatewayId defaults to the organization's default active gateway;
    • a pending, unexpired link for the same invoice is returned instead of creating a second one.

    The response contains url ({APP_URL}/pay/{token}), amount, currency, status, expiresAt. Share the URL or let Alya Books add it: while a pending link exists, POST /invoices/{id}/send adds a Pay now button to the email.

    GET /invoices/{id}/payment-links lists an invoice's links; GET /payment-links?status=pending pages all of them; POST /payment-links/{id}/cancel cancels a pending link.

    Settlement

    The public pay page calls the pay-link function, which asks the gateway for a checkout session and redirects the buyer. Confirmation arrives on payment-webhook?provider=<provider>&org=<organizationId>, verified with the gateway's signature (Stripe Stripe-Signature, Telr and Tap HMAC secrets, PayTabs server key). The settle_payment_link function then:

    1. marks the link paid with the provider reference (idempotent: a repeated notification is ignored);
    2. inserts a payment on the invoice with method: online, source: gateway;
    3. updates paidAmount / paymentStatus and emits payment_link.paid (and invoice.paid when fully settled).

    If the buyer returns before the webhook fired, the pay page reconciles by fetching the status from the gateway. The mock gateway settles through Simulate payment on the page.

    Bank feeds

    Transactions arrive from a live connection (Lean Technologies, Tarabut, or the mock feed; synced twice a day and on demand) or from statement rows you post yourself:

    curl -X POST "$BASE/bank/import" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" -d '{
      "currency": "AED",
      "rows": [
        { "Date": "2027-02-03", "Description": "TRF INV-2027-00012 ACME TRADING", "Credit": "5250.00", "Debit": "", "Reference": "FT27034ABC" }
      ]
    }'
    

    Rows are objects keyed by the bank's own column names; Alya Books recognises date, amount or debit/credit, description, reference, counterparty name and IBAN in the usual spellings. A row id is derived from date, amount and text, so re-importing overlapping statements never duplicates. The response counts imported, duplicates, suggested, autoMatched.

    POST /bank/sync pulls the live connections (connectionId to restrict) and, with rematch: true, rescores everything still open.

    Matching

    For every transaction the matcher scores open documents in the same direction (credits against issued invoices, debits against accepted incoming invoices):

    SignalScore
    Invoice number found in description/reference+0.6
    Amount equals the outstanding balance+0.3 (invoice total +0.2, partial +0.1)
    Counterparty name overlaps the customer/supplier nameup to +0.2
    TRN in the text+0.2
    Booked within 60 days after the issue date+0.05

    Candidates ≥ 0.5 make the transaction suggested (top five kept in suggestions); ≥ 0.9 with a clear lead over the runner-up is matched automatically when the organization's bankAutoMatch switch is on. GET /bank/transactions?status=suggested pages transactions with their candidates.

    Confirm, change or undo:

    curl -X POST "$BASE/bank/transactions/$TXN_ID/match" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" -d '{ "invoiceId": "…" }'
    curl -X POST "$BASE/bank/transactions/$TXN_ID/unmatch" -H "X-API-KEY: $KEY"
    curl -X POST "$BASE/bank/transactions/$TXN_ID/ignore" -H "X-API-KEY: $KEY"
    

    A confirmed match inserts a payment (source: bank_feed, the bank reference, the transaction amount unless amount is given) and emits bank.transaction_matched; unmatching deletes that payment and returns the transaction to unmatched.

    MCP and CLI

    MCP: create_payment_link, list_payment_links, cancel_payment_link, list_bank_transactions, match_bank_transaction, ignore_bank_transaction, import_bank_statement, sync_bank_feeds. CLI: alyabooks pay-link create <invoiceId>, alyabooks pay-link list --status pending, alyabooks bank transactions --status suggested, alyabooks bank match <txnId> --invoice-id <id>, alyabooks bank import -f rows.json, alyabooks bank sync --rematch.