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)
- Partner ERP calls
POST /v1/invoices— creates the invoice indraftstatus. Nothing is sent to the FTA yet. - Partner ERP calls
POST /v1/invoices/submitwith the draft invoice id(s) — TrustBill flips them toqueuedand enqueues the transform pipeline. - TrustBill's pipeline runs automatically:
queued → transformed → validated → delivered(PINT-AE XML generation + ASP submission). - The ASP (Tron-Stride or Storecove) delivers the XML to the FTA/Peppol network.
Inbound Flow (FTA → TrustBill → Partner ERP)
- The ASP sends an inbound webhook to TrustBill (
POST /v1/webhooks/asp/tron-strideor/storecove) when the FTA acknowledges or rejects the invoice. - TrustBill verifies the ASP's HMAC signature + timestamp, then updates the invoice status to
acknowledgedorrejected. - Partner ERP retrieves the updated status by calling
GET /v1/invoices/{id}(orGET /v1/invoiceswith 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
currencyis fixed to"AED"— multi-currency is not supported yet.vatRateis a decimal fraction (0–1), e.g.0.05for 5% — not a percentage like5.00.invoiceTypeonly accepts"sale"or"purchase"today. Credit/debit notes are not yet exposed on the public create endpoint — see Section 4.5.subtotal/vat_amount/totalare not sent by the client — TrustBill computestotalsfromlinesserver-side and returns it in the response.buyer/selleraccept 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
| Operation | Endpoint | Notes |
|---|---|---|
| List invoices | GET /v1/invoices | Filters: status, invoiceType, dateFrom, dateTo, q, cursor, limit (max 200) |
| Get one invoice | GET /v1/invoices/{id} | Full invoice incl. lines, totals, pipeline stages, errors |
| Delete draft | DELETE /v1/invoices/{id} | Only draft invoices are deletable (204). Submitted invoices must be reversed via a credit note, not deleted. |
| Retry rejected | POST /v1/invoices/{id}/retry | Only rejected invoices can be retried; re-enqueues the pipeline (202) |
| Bulk patch drafts | PATCH /v1/invoices/bulk | Body: { 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)
| Limit | Value |
|---|---|
| Max rows per file | 1,000 invoices |
| Sandbox tenants | 100 invoices lifetime cap (pending consultancy approval) |
| Partial success | Yes — each row succeeds/fails independently; a bad row does not roll back the batch |
| Duplicate invoice number | Draft 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, orGET /v1/invoices?status=delivered&status=acknowledged&status=rejectedfor 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.
| Status | Meaning | Terminal? |
|---|---|---|
| draft | Created, not yet submitted | No |
| queued | Submitted, waiting for pipeline | No |
| transformed | PINT-AE XML generated | No |
| validated | Passed schema/Schematron validation | No |
| blocked_no_credit | Consultancy has insufficient billing credit | Yes |
| delivered | Sent to FTA via ASP; awaiting FTA ack | Yes (pending ack) |
| acknowledged | FTA confirmed receipt/validity | Yes |
| rejected | FTA or ASP rejected the invoice | Yes — retry creates a new pipeline run |
Technical Specifications
| Specification | Value |
|---|---|
| Base path | /v1/invoices (relative to the TrustBill API host) |
| Authentication | Bearer JWT; per-tenant API credential for server-to-server integration |
| Idempotency | Required Idempotency-Key header on all write endpoints |
| Request Format | JSON (multipart/form-data for CSV bulk import) |
| Response Format | JSON |
| Charset | UTF-8 |
| List page size | Default 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
| Field | Type | Required | Notes |
|---|---|---|---|
| number | string (1–64) | Yes | Invoice number from the ERP |
| issueDate | date | Yes | YYYY-MM-DD |
| dueDate | date | No | YYYY-MM-DD |
| currency | literal | No (defaults) | Only "AED" is accepted |
| invoiceType | enum | No (defaults "sale") | "sale" | "purchase" |
| buyer | object | Yes | See 6.4 below |
| seller | object | Yes | See 6.4 below; must differ from buyer |
| lines | array | Yes | 1–200 line items; see 6.5 |
| totals / subtotal / total | — | Not sent by client | Computed server-side from lines and returned in the response |
Buyer / Seller (Customer) Object
| Field | Type | Required | Notes |
|---|---|---|---|
| id | uuid | No | Reuse an existing customer instead of a full object |
| name | string | Yes (if no id) | Legal name |
| trn | string | No | Exactly 15 digits; server upserts on (tenant, TRN) if provided |
| country | ISO country code | Yes (if no id) | e.g. AE |
| address | object | No | line1, line2?, city, ... (see 6.6) |
| email / phone | string | No | Optional contact fields |
| kind | enum | No (default "buyer") | "buyer" | "seller" | "both" |
Line Item Object
| Field | Type | Required | Notes |
|---|---|---|---|
| description | string | Yes | Non-empty |
| quantity | number | Yes | Must be positive (> 0) |
| unitPrice | number | Yes | Non-negative, excludes VAT |
| vatRate | number | Yes | 0–1 decimal fraction (0.05 = 5%) |
| taxCategory | enum | No (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 |
| lineTotal | — | Not sent by client | Computed 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 Code | Typical Cause | Action |
|---|---|---|
| 400 | invalid_body, validation_failed — bad TRN, bad dates, buyer = seller | Fix payload and retry; do not blind-retry |
| 401 | missing_authorization_header — expired/missing JWT | Re-authenticate and retry |
| 403 | kyb_required — tenant suspended/rejected | Contact TrustBill support |
| 404 | invoice_not_found | Verify invoice id and tenant scope |
| 409 | invoice_not_deletable, invoice_not_retriable, invoice_mode_mismatch | Check invoice status/mode before the call |
| 413 | bulk_payload_too_large — CSV > 5 MB or > 1,000 rows | Split the file |
| 422 | idempotency_required / idempotency_conflict | Always send a unique Idempotency-Key; reuse the same key only for true retries |
Integration Steps
Onboarding Process
- Account Setup: TrustBill creates an accounting-firm (consultancy) account for Partner ERP, pending super-admin approval
- Credential Provisioning: Define how Partner ERP's backend authenticates per SME client
- Sandbox Testing: Create SME clients in sandbox/test mode and exercise create → submit → status-poll end to end
- Fast-follows scoped: credit/debit notes on the public API, outbound status webhook
- 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-Keyper write request - ☐ Build invoice create module mapping ERP invoice → TrustBill's
InvoiceCreateInputshape (note the 0–1vatRatescale) - ☐ 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_sameerror - Call
POST /v1/invoices/submit→ status movesdraft → queued, then progresses through the pipeline - Poll
GET /v1/invoices/{id}until a terminal status (delivered/acknowledged/rejected) - Retry a
rejectedinvoice viaPOST /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
- WhatsApp: +971 52 260 9313
- Email: info@trustbill.ae
- Documentation: https://docs.trustbill.ae
- API Status: https://status.trustbill.ae
Sales & Partnership
- WhatsApp: +971 52 260 9313
- Email: info@trustbill.ae
Appendix
Glossary
| Term | Definition |
|---|---|
| ASP | Accredited Service Provider - FTA-approved e-invoicing intermediary |
| PINT-AE | Peppol International UAE - Official e-invoice XML format |
| FTA | Federal Tax Authority - UAE tax authority |
| TRN | Tax Registration Number - 15-digit UAE business identifier |
| Peppol | Pan-European Public Procurement On-Line - Global e-document network |
| Submission Mode | Per-company setting (test / sandbox / live) |
| Idempotency-Key | Required 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