← Back to Documentation

TrustBill ERP Integration Guide

Partnership Documentation for E-Invoicing Integration | Version 1.1 | July 2026

Partnership Overview

This document describes how Partner ERP integrates with TrustBill, a UAE FTA-accredited e-invoicing platform, so Partner ERP's clients can issue compliant e-invoices without leaving their ERP. It reflects TrustBill's current, shipped API surface.

Executive Summary

TrustBill is an FTA-accredited service provider (ASP) that converts invoices into PINT-AE XML and delivers them to the FTA over the Peppol network via its ASP partners (Tron-Stride, Storecove). Partner ERP is your cloud ERP system providing accounting, invoicing, and business management.

Key Benefits of Integration:

  • Partner ERP clients get built-in e-invoicing compliance without switching systems
  • Invoice status (delivered / acknowledged / rejected) is visible back in the ERP
  • Accounting-firm account model lets Partner ERP manage many SME clients centrally
  • CSV bulk import supports high-volume invoice migration

Account Model

TrustBill offers two account types relevant to this partnership:

Accounting Firm (Consultancy) Account

For Partner ERP, acting as a consultancy

  • Manage multiple SME clients from a single dashboard
  • Define pricing plans/markups for clients
  • Monitor all client e-invoicing activity
  • Requires super-admin approval before inviting SME clients

Demo Access: accountingfirm@trustbill.ae / 123123123

SME Account

For each Partner ERP end client (one SME = one TRN)

  • Creates and submits e-invoices (draft → submit → FTA)
  • Tracks invoice status and pipeline in real time
  • Manages TRN, company profile, and submission mode (Test / Sandbox / Live)

Demo Access: worldexploreroff@gmail.com / c@123123

Integration Architecture

The invoice lifecycle is request/response on the way out and polling on the way back today — see the note in Section 5 about outbound webhooks.

Outbound Flow (Partner ERP → TrustBill)

  1. Partner ERP calls POST /v1/invoices — creates the invoice in draft status. Nothing is sent to the FTA yet.
  2. Partner ERP calls POST /v1/invoices/submit with the draft invoice id(s) — TrustBill flips them to queued and enqueues the transform pipeline.
  3. TrustBill's pipeline runs automatically: queued → transformed → validated → delivered (PINT-AE XML generation + ASP submission).
  4. The ASP (Tron-Stride or Storecove) delivers the XML to the FTA/Peppol network.

Inbound Flow (FTA → TrustBill → Partner ERP)

  1. The ASP sends an inbound webhook to TrustBill (POST /v1/webhooks/asp/tron-stride or /storecove) when the FTA acknowledges or rejects the invoice.
  2. TrustBill verifies the ASP's HMAC signature + timestamp, then updates the invoice status to acknowledged or rejected.
  3. Partner ERP retrieves the updated status by calling GET /v1/invoices/{id} (or GET /v1/invoices with filters) — see Section 5 for the current polling-based model.

Authentication

TrustBill's API is authenticated with a Bearer JWT issued at sign-in, sent as a standard Authorization: Bearer <token> header. There is no OAuth 2.0 authorization-code / client-credentials flow today — please disregard any documentation implying otherwise.

Credential Provisioning

TrustBill's current auth model is a user-session JWT (obtained by signing in to a TrustBill account). For server-to-server ERP integration, TrustBill will issue Partner ERP a per-tenant API credential to enable headless authentication without requiring a login flow.

Request Header (current model):

Authorization: Bearer {jwt_token}
Content-Type: application/json
Idempotency-Key: {unique_key_per_request}

Idempotency-Key is mandatory

Every write endpoint (POST /v1/invoices, POST /v1/invoices/bulk, POST /v1/invoices/:id/retry) requires an Idempotency-Key header (1–128 characters). Requests without it are rejected with idempotency_required. Re-sending the same key + body returns the original cached response instead of creating a duplicate — safe for network retries.

Create Invoice (draft)

Endpoint: POST /v1/invoices

Request Body:

{ "number": "INV-2026-001", "issueDate": "2026-07-29", "dueDate": "2026-08-28", "currency": "AED", "invoiceType": "sale", "buyer": { "name": "Buyer Company LLC", "trn": "100000000000000", "country": "AE", "email": "ap@buyer.example", "address": { "line1": "123 Business Street", "city": "Dubai", "country": "AE" } }, "seller": { "name": "Partner ERP Client LLC", "trn": "100000000000001", "country": "AE" }, "lines": [ { "description": "Consulting Services", "quantity": 10, "unitPrice": 100.00, "vatRate": 0.05, "taxCategory": "standard_5" } ] }

Field Notes

  • currency is fixed to "AED" — multi-currency is not supported yet.
  • vatRate is a decimal fraction (0–1), e.g. 0.05 for 5% — not a percentage like 5.00.
  • invoiceType only accepts "sale" or "purchase" today. Credit/debit notes are not yet exposed on the public create endpoint — see Section 4.5.
  • subtotal / vat_amount / total are not sent by the client — TrustBill computes totals from lines server-side and returns it in the response.
  • buyer/seller accept either a full object (server creates/upserts the customer) or { id: "<uuid>" } to reuse an existing customer record.

Response (201 Created) — abbreviated:

{ "id": "3fbb6f2e-....-uuid", "tenantId": "....", "number": "INV-2026-001", "status": "draft", "issueDate": "2026-07-29", "dueDate": "2026-08-28", "invoiceType": "sale", "buyer": { "id": "...", "name": "Buyer Company LLC", "trn": "100000000000000", ... }, "seller": { "id": "...", "name": "Partner ERP Client LLC", ... }, "lines": [ { "id": "...", "description": "Consulting Services", "quantity": 10, "unitPrice": 100, "vatRate": 0.05, "lineTotal": 1050, "taxCategory": "standard_5" } ], "totals": { "subtotal": 1000, "tax": 50, "total": 1050, "currency": "AED" }, "pipeline": [], "errors": [], "isSandbox": false, "submissionMode": "live", "source": "manual" }

Response (400 — validation failure):

{ "code": "invalid_body", "humanMessage": "Some invoice fields didn't pass validation.", "meta": { "issues": ["buyer.trn: invalid_string"] } }

Credit Notes, Debit Notes

TrustBill's ASP payload layer is prepared for credit_note and debit_note document types. The public POST /v1/invoices endpoint currently accepts invoiceType: "sale" | "purchase". Credit and debit note support will be added to the partner-facing API as part of this integration.

Submit Invoice(s) for Delivery

Creating an invoice does not send it to the FTA. Submission is an explicit, separate call so ERPs can create-then-review before delivery.

Endpoint: POST /v1/invoices/submit

{ "ids": ["3fbb6f2e-....-uuid"] }

Accepts 1–200 invoice UUIDs per call. Only invoices currently in draft, in the tenant's active submission mode, are queued — everything else is silently skipped (idempotent re-submit).

Response (200):

{ "submitted": 1, "ids": ["3fbb6f2e-....-uuid"] }

Read, List, Delete, Retry

OperationEndpointNotes
List invoicesGET /v1/invoicesFilters: status, invoiceType, dateFrom, dateTo, q, cursor, limit (max 200)
Get one invoiceGET /v1/invoices/{id}Full invoice incl. lines, totals, pipeline stages, errors
Delete draftDELETE /v1/invoices/{id}Only draft invoices are deletable (204). Submitted invoices must be reversed via a credit note, not deleted.
Retry rejectedPOST /v1/invoices/{id}/retryOnly rejected invoices can be retried; re-enqueues the pipeline (202)
Bulk patch draftsPATCH /v1/invoices/bulkBody: { ids: [...], patch: { issueDate?, dueDate?, number?, invoiceType? } } — draft only

Bulk Invoice Import (CSV)

For migrating existing invoices or high-volume batches, TrustBill accepts a CSV upload (not a JSON array) as multipart/form-data.

Endpoint: POST /v1/invoices/bulk (multipart, one CSV file part, max 5 MB, Idempotency-Key header required)

LimitValue
Max rows per file1,000 invoices
Sandbox tenants100 invoices lifetime cap (pending consultancy approval)
Partial successYes — each row succeeds/fails independently; a bad row does not roll back the batch
Duplicate invoice numberDraft rows are upserted (updated); non-draft rows with the same number are rejected

Response (200) — abbreviated:

{ "summary": { "total": 2, "succeeded": 2, "updated": 0, "failed": 0 }, "results": [ { "row": 1, "invoiceNumber": "INV-2026-001", "status": "created", "invoice": { ... } }, { "row": 2, "invoiceNumber": "INV-2026-002", "status": "created", "invoice": { ... } } ] }

Getting Status Back Into Partner ERP

Important — no outbound webhook to partner systems today

TrustBill's existing webhook infrastructure (POST /v1/webhooks/asp/tron-stride, /storecove) is inbound only — it is how the ASP notifies TrustBill of FTA outcomes. TrustBill does not currently push status changes out to a partner-configured URL.

Current Model: Polling

Until outbound webhooks are built, Partner ERP should poll for status changes:

  • Endpoint: GET /v1/invoices/{id} for a single invoice, or GET /v1/invoices?status=delivered&status=acknowledged&status=rejected for a batch
  • Recommended interval: every 2–5 minutes while an invoice is in a non-terminal state
  • Terminal states — stop polling: delivered, acknowledged, blocked_no_credit, rejected

Outbound Webhook

TrustBill will add a partner-facing outbound webhook (register a URL, receive invoice.status_changed events, HMAC-signed, with retry/backoff) as part of this integration. The existing inbound ASP webhook pipeline (AspWebhookService) already implements HMAC + timestamp + nonce verification and tenant-scoped delivery — the same pattern will be reused for the outbound notifier.

Invoice Status Values (live enum)

Statuses are forward-only — an invoice never moves backward; a retry produces a new pipeline run, not a rewind.

StatusMeaningTerminal?
draftCreated, not yet submittedNo
queuedSubmitted, waiting for pipelineNo
transformedPINT-AE XML generatedNo
validatedPassed schema/Schematron validationNo
blocked_no_creditConsultancy has insufficient billing creditYes
deliveredSent to FTA via ASP; awaiting FTA ackYes (pending ack)
acknowledgedFTA confirmed receipt/validityYes
rejectedFTA or ASP rejected the invoiceYes — retry creates a new pipeline run

Technical Specifications

SpecificationValue
Base path/v1/invoices (relative to the TrustBill API host)
AuthenticationBearer JWT; per-tenant API credential for server-to-server integration
IdempotencyRequired Idempotency-Key header on all write endpoints
Request FormatJSON (multipart/form-data for CSV bulk import)
Response FormatJSON
CharsetUTF-8
List page sizeDefault 25, max 200 (limit query param)

Data Format Requirements

  • TRN: exactly 15 digits (regex-validated) for both buyer and seller
  • Currency: fixed to AED — no other value is accepted yet
  • VAT Rate: decimal fraction between 0 and 1 (e.g. 0.05 = 5%, 0 = zero-rated/exempt)
  • Dates: ISO 8601 date only (YYYY-MM-DD), no time component
  • Invoice number: 1–64 characters, unique per tenant + submission mode
  • Country codes: ISO 3166-1 alpha-2 (e.g. AE)

Invoice Field Specifications

FieldTypeRequiredNotes
numberstring (1–64)YesInvoice number from the ERP
issueDatedateYesYYYY-MM-DD
dueDatedateNoYYYY-MM-DD
currencyliteralNo (defaults)Only "AED" is accepted
invoiceTypeenumNo (defaults "sale")"sale" | "purchase"
buyerobjectYesSee 6.4 below
sellerobjectYesSee 6.4 below; must differ from buyer
linesarrayYes1–200 line items; see 6.5
totals / subtotal / totalNot sent by clientComputed server-side from lines and returned in the response

Buyer / Seller (Customer) Object

FieldTypeRequiredNotes
iduuidNoReuse an existing customer instead of a full object
namestringYes (if no id)Legal name
trnstringNoExactly 15 digits; server upserts on (tenant, TRN) if provided
countryISO country codeYes (if no id)e.g. AE
addressobjectNoline1, line2?, city, ... (see 6.6)
email / phonestringNoOptional contact fields
kindenumNo (default "buyer")"buyer" | "seller" | "both"

Line Item Object

FieldTypeRequiredNotes
descriptionstringYesNon-empty
quantitynumberYesMust be positive (> 0)
unitPricenumberYesNon-negative, excludes VAT
vatRatenumberYes0–1 decimal fraction (0.05 = 5%)
taxCategoryenumNo (default "standard_5")standard_5, zero_rated_export, zero_rated_healthcare, zero_rated_education, exempt_financial, exempt_residential_rent, reverse_charge_designated_zone, out_of_scope
lineTotalNot sent by clientComputed server-side (quantity × unitPrice, VAT-inclusive)

Address Object Format

{ "line1": "123 Business Street", "line2": "Suite 400", "city": "Dubai", "country": "AE" }

Error Handling

Partner ERP should implement robust error handling around TrustBill's domain-error shape ({ code, humanMessage, meta? }):

HTTP CodeTypical CauseAction
400invalid_body, validation_failed — bad TRN, bad dates, buyer = sellerFix payload and retry; do not blind-retry
401missing_authorization_header — expired/missing JWTRe-authenticate and retry
403kyb_required — tenant suspended/rejectedContact TrustBill support
404invoice_not_foundVerify invoice id and tenant scope
409invoice_not_deletable, invoice_not_retriable, invoice_mode_mismatchCheck invoice status/mode before the call
413bulk_payload_too_large — CSV > 5 MB or > 1,000 rowsSplit the file
422idempotency_required / idempotency_conflictAlways send a unique Idempotency-Key; reuse the same key only for true retries

Integration Steps

Onboarding Process

  1. Account Setup: TrustBill creates an accounting-firm (consultancy) account for Partner ERP, pending super-admin approval
  2. Credential Provisioning: Define how Partner ERP's backend authenticates per SME client
  3. Sandbox Testing: Create SME clients in sandbox/test mode and exercise create → submit → status-poll end to end
  4. Fast-follows scoped: credit/debit notes on the public API, outbound status webhook
  5. Production Go-Live: Switch SME clients to live submission mode once FTA registration/payment is complete

Development Checklist

  • ☐ Implement Bearer-token auth (confirm final credential model with TrustBill)
  • ☐ Generate a unique Idempotency-Key per write request
  • ☐ Build invoice create module mapping ERP invoice → TrustBill's InvoiceCreateInput shape (note the 0–1 vatRate scale)
  • ☐ Build explicit submit step (POST /v1/invoices/submit) — don't assume create = submit
  • ☐ Build a polling job for non-terminal invoices (2–5 min interval)
  • ☐ Handle the documented domain-error codes
  • ☐ Test with the sandbox SME demo account before production TRNs

Testing Requirements

Test Cases

  • Create a draft invoice → expect status: "draft", totals computed correctly from lines
  • Submit invalid TRN (not 15 digits) → expect 400 invalid_body
  • Submit invoice with buyer = seller → expect buyer_seller_same error
  • Call POST /v1/invoices/submit → status moves draft → queued, then progresses through the pipeline
  • Poll GET /v1/invoices/{id} until a terminal status (delivered/acknowledged/rejected)
  • Retry a rejected invoice via POST /v1/invoices/{id}/retry → expect 202 and pipeline re-run
  • Re-send the same request with the same Idempotency-Key → expect the identical cached response, not a duplicate invoice
  • Upload a CSV with one bad row and one good row → expect partial success in results

Support & Contact

Technical Support

Sales & Partnership

  • WhatsApp: +971 52 260 9313
  • Email: info@trustbill.ae

Appendix

Glossary

TermDefinition
ASPAccredited Service Provider - FTA-approved e-invoicing intermediary
PINT-AEPeppol International UAE - Official e-invoice XML format
FTAFederal Tax Authority - UAE tax authority
TRNTax Registration Number - 15-digit UAE business identifier
PeppolPan-European Public Procurement On-Line - Global e-document network
Submission ModePer-company setting (test / sandbox / live)
Idempotency-KeyRequired header on write endpoints so a network retry cannot create a duplicate invoice/batch

Compliance References

  • UAE Cabinet Decision 106/2025 - E-invoicing penalties
  • FTA Ministerial Decision 244/2025 - ASP regulations
  • PINT-AE Technical Specification v1.1
  • Peppol BIS Billing 3.0 Standard