Aigentrix E-Invoice API
Create, validate, submit and track UAE Peppol e-invoices from your ERP or accounting system. One API key, no JWT to manage. Every code list and rule id on this page comes from the production PINT-AE v1.04 ruleset.
https://app.aigentrix.ai/external/api/v1X-API-KEYGetting started
Six steps from zero to a delivered invoice. If you already have an API key and a company id, skip to the quick start below.
Quick start — create, then submit
# 1. Create the invoice — it is stored as DRAFT, nothing is sent yet
curl -X POST "https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/createFull" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $AIGENTRIX_API_KEY" \
-d '{
"companyId": 20,
"documentId": "INV-2026-001",
"issueDate": "2026-09-06",
"invoiceTypeCode": "380",
"invoiceTransactionType": "00000000",
"documentCurrencyCode": "AED",
"paymentDueDate": "2026-10-06",
"sellerRegisteredName": "ABC Trading LLC",
"sellerVatTrn": "100123456700003",
"sellerAddressLine1": "Sheikh Zayed Road",
"sellerCity": "Dubai",
"sellerCountrySubdivision": "DXB",
"sellerCountryCode": "AE",
"buyerRegisteredName": "XYZ Corp LLC",
"buyerVatTrn": "100987654300003",
"buyerAddressLine1": "Al Wahda Street",
"buyerCity": "Sharjah",
"buyerCountrySubdivision": "SHJ",
"buyerCountryCode": "AE",
"lineExtensionTotal": 1000.00,
"taxAmount": 50.00,
"totalIncludingTax": 1050.00,
"payableAmount": 1050.00,
"lines": [{
"lineNumber": 1,
"itemName": "Consulting services",
"quantity": 10, "quantityUom": "HUR",
"unitPrice": 100.00, "lineNetAmount": 1000.00,
"taxCategory": "S", "taxRatePercent": 5,
"taxScheme": "VAT", "lineTaxAmount": 50.00,
"inclVatAmount": 1050.00
}],
"allowances": [],
"payments": [{ "paymentMeansCode": "30" }],
"terms": []
}'
# → { "success": true, "status": "CREATED", "entryId": 45426, "documentId": "INV-2026-001" }
# 2. Submit it
curl -X PUT "https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/45426" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $AIGENTRIX_API_KEY" \
-d '{ "id": 45426, "status": "SUBMITTED" }'
# 3. Check what happened
curl "https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/45426/validationErrors" \
-H "X-API-KEY: $AIGENTRIX_API_KEY"👤
Create your Aigentrix account
Sign up on the Aigentrix platform. You need a valid business email address.
- 1Go to https://app.aigentrix.ai and click Get Started.
- 2Enter your full name, business email and a secure password.
- 3Verify your email address using the confirmation link.
- 4Log in with your credentials.
If your organisation already has an account, ask your admin to invite you rather than creating a second organisation — an API key is scoped to exactly one organisation.
🏢
Create your organisation
An organisation is the top-level entity holding your companies, users and subscription.
- 1Go to Settings → Organisation.
- 2Click "Create Organisation" and enter your legal organisation name.
- 3Set the default country and currency.
- 4Click "Save".
You never pass an organisationId to the API — it is resolved server-side from your API key.
🏭
Add a company
A company is the legal entity that issues or receives e-invoices. Its master record supplies the seller defaults for every invoice you create.
- 1Go to Settings → Companies → Add Company.
- 2Enter the registered name, the VAT TRN (15 digits, starts with 1, ends with 03) and the trade licence number.
- 3Set the country to AE, the emirate (AUH / DXB / SHJ / AJM / UAQ / RAK / FUJ) and the currency to AED.
- 4Click "Save" and note the Company ID — this is companyId in every API call.
Blank seller fields in a request are filled from this record, so keep the legal registration id, type and authority complete — otherwise documents fail rules ibr-150-ae, ibr-181-ae and ibr-172-ae.
📄
Enable e-invoicing for the company
Activate the e-invoice module so the company can submit, validate and track Peppol documents.
- 1Open the company record and go to the E-Invoice tab.
- 2Toggle "Enable E-Invoice" to ON.
- 3Set the default environment — SANDBOX or LIVE. This becomes einvoiceDefaultEnv.
- 4The Peppol participant id is derived as 0235: plus your TIN. Override it only if you have been told to.
- 5Click "Save Configuration".
SANDBOX routes to the Peppol TEST network and LIVE to production. Both use the same API, the same rules and the same validation.
🔑
Generate an API key
API keys let your ERP or scripts call Aigentrix without user login tokens. There is no JWT to manage.
- 1Go to Settings → API Keys → Generate New Key.
- 2Give the key a descriptive label, for example ERP Integration – Production.
- 3Click "Generate" and copy the key immediately — it is shown only once.
- 4Store it securely, for example as AIGENTRIX_API_KEY in your environment.
Send the key as the X-API-KEY header on every request. A missing, invalid or revoked key returns 401. Keys can be revoked at any time.
🚀
Make your first call
List your companies, create a draft invoice, then submit it. Three requests, end to end.
- 1GET /companies — note the id in the response, this is your companyId.
- 2POST /eInvoiceEntry/createFull — the entry is stored as DRAFT and nothing is sent yet.
- 3PUT /eInvoiceEntry/{entryId} with { "id": …, "status": "SUBMITTED" } — exactly what the Submit button does.
- 4GET /eInvoiceEntry/{entryId} to follow the status, or subscribe to webhooks instead of polling.
- 5If it fails, GET /eInvoiceEntry/{entryId}/validationErrors returns the failed rule ids.
Want to try before writing anything? POST to /eInvoiceEntry/validate — it runs the full XSD and Schematron validation with no database write.
Authentication and conventions
Every request carries your organisation's API key. A key belongs to exactly one organisation, and the companyId you send must be one of that organisation's companies.
No X-API-KEY headerKey not recognised{ "errorKey": "Access denied" }{ "error": "…" }Environments
environment=SANDBOX (the default) routes to the Peppol test network; environment=LIVE routes to production. Both use the same API, the same rules and the same validation. The company's own default is einvoiceDefaultEnv.
Data conventions
| Topic | Rule |
|---|---|
| Dates | yyyy-MM-dd. A date-time is accepted and the time part is dropped. |
| Amounts | At most 2 decimals. The exchange rate takes at most 6. |
| Strings | Trimmed server-side. A blank string is treated as not provided. |
| Country codes | ISO 3166-1 alpha-2, e.g. AE, SE. |
| Country subdivision | For AE addresses one of AUH DXB SHJ AJM UAQ RAK FUJ; free text elsewhere. |
| Currency codes | ISO 4217, e.g. AED, USD. |
| Unit of measure | UN/ECE Rec 20, e.g. EA, H87, HUR, KGM, C62. |
| Unknown JSON keys | Ignored silently — a typo in a field name drops the value. Always check the read-back. |
// Node.js / browser
const response = await fetch(
"https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/createFull",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": process.env.AIGENTRIX_API_KEY,
},
body: JSON.stringify(invoicePayload),
}
);
const data = await response.json();
if (!data.success) {
// A business error still arrives with HTTP 200 — check the flag.
throw new Error(data.errorKey ?? "createFull failed");
}
console.log(data.entryId);Document lifecycle and statuses
Two independent status fields: status tracks delivery over the Peppol network, taxStatus tracks reporting to the FTA.
status — the happy path
Stored, not submitted
Queued for validation
Being converted
XSD + Schematron passed
Handed to the access point
Accepted by the receiver
Business acknowledgement received
Everything else
Editable vs locked. DRAFT, VALIDATION_FAILED, REJECTED and TRANSMISSION_FAILED accept a full update. At every other status only userField01–userField10 can change.
taxStatus — FTA reporting
Independent of the delivery status above. An invoice can be DELIVERED on the network while its tax reporting is still in progress.
NOT_INITIATED
→ REPORTING_INITIATED
→ REPORTING_CONFIRMED / TDD_VALIDATION_PASSED | TDD_VALIDATION_FAILED
→ ACKNOWLEDGED | REJECTED
Withdrawal path: WITHDRAW_INITIATED → WITHDRAWNAPI reference
All 29 endpoints sit under /external/api/v1 and require the X-API-KEY header. Path parameters shown in braces must be replaced with real values.
Try it in Postman
The collection carries every endpoint plus nine verified scenario requests and seven example webhook payloads, with the environment variables pre-configured.
1Companies
Find the companyId you pass to every other call. No organisationId is needed — it is resolved from your API key.
https://app.aigentrix.ai/external/api/v1/companiesList companies
Paginated list of the companies your API key can access. The id in each row is the companyId used everywhere else.
Parameters
pageoptZero-based page number. Default 0.
perPageoptPage size. Default 10.
sortByoptField to sort by. Default createdAt.
orderByoptasc or desc. Default desc.
Notes
{
"totalRecords": 1,
"companies": [
{
"id": 20,
"code": "COMP001",
"nameEN": "Sample Trading LLC",
"cityEN": "Dubai",
"email": "finance@sampletrading.ae",
"taxVatRegistrationNumberEN": "100123456700003",
"viaPeppol": true,
"isInvoice": true
}
]
}https://app.aigentrix.ai/external/api/v1/companies/{companyId}Get company by ID
One company, including its TRN, TIN and Peppol participant id. The company is verified server-side to belong to your key's organisation.
Parameters
companyIdreqThe company id from 1.1.
Notes
{
"id": 20,
"code": "COMP001",
"nameEN": "Sample Trading LLC",
"cityEN": "Dubai",
"email": "finance@sampletrading.ae",
"taxVatRegistrationNumberEN": "100123456700003",
"viaPeppol": true,
"isInvoice": true
}2Create an invoice
One JSON request creates one invoice. The entry is stored as DRAFT; submitting is a separate call.
https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/createFullCreate e-invoice entry (full JSON)
Creates one invoice from JSON. The entry is stored as DRAFT and nothing is sent until you submit it. Every accepted key is listed in the field reference below.
Content-Type: application/json
Notes
{
"companyId": 20,
"invoiceRef": "IIL-1001309",
"documentId": "IIL-1001309",
"issueDate": "2026-07-14",
"invoiceTypeCode": "380",
"invoiceTransactionType": "00000000",
"documentCurrencyCode": "AED",
"paymentDueDate": "2026-09-12",
"contractDocumentReference": "SIL-301358",
"sellerRegisteredName": "TRONSTRIDE FZC",
"sellerVatTrn": "104196887400003",
"sellerAddressLine1": "Business Centre, Sharjah Publishing City Freezone",
"sellerCity": "Sharjah",
"sellerCountrySubdivision": "SHJ",
"sellerCountryCode": "AE",
"sellerLegalRegistrationId": "714/2015",
"sellerLegalRegistrationType": "TL",
"sellerLegalRegistrationAuthority": "Dubai Economic Department",
"buyerRegisteredName": "Habib Mohammad Sharif Abdulla Almulla",
"buyerVatTrn": "100711669800003",
"buyerAddressLine1": "Dubai, UAE",
"buyerCity": "Dubai",
"buyerCountrySubdivision": "DXB",
"buyerCountryCode": "AE",
"lineExtensionTotal": 37500.00,
"docLevelDiscount": 0.00,
"docLevelCharges": 0.00,
"taxAmount": 1875.00,
"totalIncludingTax": 39375.00,
"roundingAmount": 0.00,
"payableAmount": 39375.00,
"lines": [
{
"lineNumber": 1,
"itemName": "Safe Oilgo",
"itemDescription": "Safe Oilgo",
"sellerItemId": "ILFGICS003",
"itemCountryOrigin": "AE",
"quantity": 15.0,
"quantityUom": "H87",
"unitPrice": 2500.00,
"priceBaseQty": 1.0,
"lineNetAmount": 37500.00,
"taxCategory": "S",
"taxRatePercent": 5.0,
"taxScheme": "VAT",
"lineTaxAmount": 1875.00,
"inclVatAmount": 39375.00
}
],
"allowances": [],
"payments": [
{
"paymentMeansCode": "30",
"creditAccountIban": "AE070260001012029678901",
"creditAccountScheme": "IBAN"
}
],
"terms": [
{
"termNote": "60 days from invoice date",
"termAmount": 39375.00,
"termCurrency": "AED",
"termInstallDate": "2026-09-12"
}
]
}https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/examplesWorked examples
Returns the ten worked scenarios as ready-to-post bodies — the same cases the Easy Invoice Examples panel offers.
Notes
{
"examples": [
{
"key": "standard-aed",
"title": "Standard VAT invoice to a UAE customer",
"when": "You are VAT registered and selling inside the UAE.",
"summary": "Type 380, transaction type 00000000, AED, 5% standard-rated lines.",
"highlights": ["Buyer TRN required", "Emirate codes on both addresses"],
"body": { "...": "a complete createFull body" }
}
]
}4Manage entries
Read, list, submit, update, delete and inspect the validation result of an entry.
https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/{entryId}Get e-invoice entry by ID
Reads an entry back: every field you sent, plus status, taxStatus, timestamps, attached files and — for XML submissions — the original XML.
Parameters
entryIdreqThe entry id returned by createFull.
Notes
{
"id": 45426,
"documentIdEN": "IIL-1001309",
"invoiceTypeCode": "380",
"documentCurrencyCode": "AED",
"issueDateEN": "2026-07-14T00:00:00",
"paymentDueDate": "2026-09-12T00:00:00",
"status": "ACKNOWLEDGED",
"taxStatus": "ACKNOWLEDGED",
"supplyPartyNameEN": "TRONSTRIDE FZC",
"supplyVatIdEN": "104196887400003",
"customerPartyNameEN": "Habib Mohammad Sharif Abdulla Almulla",
"customerVatIdEN": "100711669800003",
"taxTotalTaxAmount": 1875.00,
"legalTaxInclusiveAmountEN": 39375.00,
"legalFinalPayableEN": 39375.00,
"submittedAsXml": false,
"files": [],
"createdAt": "2026-07-14T10:30:00",
"updatedAt": "2026-07-14T10:41:12"
}https://app.aigentrix.ai/external/api/v1/eInvoiceEntryList e-invoice entries
Paginated list of entries for one company over an issue-date range.
Parameters
companyIdreqFilter by company id.
startDatereqStart of the issue-date range (yyyy-MM-dd).
endDatereqEnd of the issue-date range (yyyy-MM-dd).
pageoptZero-based page number. Default 0.
perPageoptPage size. Default 10.
sortByoptField to sort by. Default createdAt.
orderByoptasc or desc. Default desc.
statusoptFilter by entry status, e.g. DRAFT, SUBMITTED, VALIDATION_PASSED, VALIDATION_FAILED, DELIVERED, ACKNOWLEDGED, REJECTED.
typeoptOUTBOUND or INBOUND.
searchStringoptFree-text search across document id and party names.
{
"content": [
{
"id": 45426,
"documentIdEN": "IIL-1001309",
"status": "ACKNOWLEDGED",
"issueDateEN": "2026-07-14T00:00:00",
"supplyPartyNameEN": "TRONSTRIDE FZC",
"customerPartyNameEN": "Habib Mohammad Sharif Abdulla Almulla",
"legalFinalPayableEN": 39375.00
}
],
"totalElements": 1,
"totalPages": 1,
"pageNumber": 0,
"pageSize": 10
}https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/{entryId}/statusTimelineStatus timeline
Every status change on the entry with its timestamp and who caused it.
Parameters
entryIdreqThe entry id.
typereqOUTBOUND or INBOUND.
{
"statusTimeline": {
"entryId": 45426,
"documentId": "IIL-1001309",
"type": "OUTBOUND",
"timeline": [
{ "status": "DRAFT", "timestamp": "2026-07-14T10:30:00", "updatedBy": "user@example.com" },
{ "status": "SUBMITTED", "timestamp": "2026-07-14T10:35:00", "updatedBy": "user@example.com" },
{ "status": "VALIDATION_PASSED", "timestamp": "2026-07-14T10:35:12", "updatedBy": "system" },
{ "status": "SENDING", "timestamp": "2026-07-14T10:35:20", "updatedBy": "system" },
{ "status": "DELIVERED", "timestamp": "2026-07-14T10:36:02", "updatedBy": "system" },
{ "status": "ACKNOWLEDGED", "timestamp": "2026-07-14T10:41:12", "updatedBy": "system" }
]
}
}https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/{entryId}Update or submit an entry
Same body shape as createFull, plus id. Submits the entry, edits an editable one, or updates user fields on a locked one.
Content-Type: application/json
Parameters
entryIdreqThe entry id.
Notes
// Submit a draft — this is what the Submit button does
{
"id": 45426,
"status": "SUBMITTED"
}
// Tag a delivered invoice with an ERP reference (locked entry)
{
"id": 45426,
"userField01": "PO-REF-2026-0917"
}https://app.aigentrix.ai/external/api/v1/eInvoiceEntryDelete e-invoice entries
Deletes one or more entries by id. Only entries in an editable status can be deleted.
Content-Type: application/json
{ "ids": [45426, 45427] }https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/{entryId}/validationErrorsGet validation errors for an entry
The stored XSD and Schematron result. Run it right after creating to confirm the document passed — an empty list means it reached VALIDATION_PASSED.
Parameters
entryIdreqThe entry id.
Notes
{
"entryId": 45426,
"documentId": "IIL-1001309",
"validationStatus": "SCHEMATRON_FAILED",
"schematronValidation": {
"failedRules": [
{
"id": "ibr-167-ae",
"severity": "fatal",
"location": "/Invoice/cac:InvoiceLine[1]",
"rule": "vatExemptReasonCode is mandatory when taxCategory is 'E'."
}
]
}
}5Documents
Download the PDF rendition or the exact UBL XML that was sent.
https://app.aigentrix.ai/external/api/v1/print/xml/{entryId}Download PDF rendition
Generates and streams the e-invoice as a PDF. Save the response body as a .pdf file.
Parameters
entryIdreqThe entry id.
fileNamereqWhich document to render: outbound_sent, outbound_ack, outbound_report_fta, outbound_confirm_fta, inbound_receive, inbound_ack, inbound_report_fta, inbound_confirm_fta.
// Binary PDF stream
Content-Type: application/pdf
Content-Disposition: attachment; filename="outbound_sent.pdf"https://app.aigentrix.ai/external/api/v1/print/orgxml/{entryId}Download raw UBL XML
Downloads the pretty-printed UBL XML stored for the entry — the exact document that went on the network. Use it to forward the signed XML to your buyer or authority.
Parameters
entryIdreqThe entry id.
fileNamereqSame values as the PDF endpoint above.
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>urn:cen.eu:en16931:2017#conformant#urn:fdc:peppol.eu:2017:poacc:billing:international:ubl:3.0</cbc:CustomizationID>
<cbc:ID>IIL-1001309</cbc:ID>
<cbc:IssueDate>2026-07-14</cbc:IssueDate>
...
</Invoice>6Validate without saving
Run the full XSD and Schematron validation without writing anything to the database.
https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/validateValidate invoices — JSON
Validates one or more invoices against the full XSD and Schematron ruleset without creating any database records. The body is a JSON array of createFull objects.
Content-Type: application/json
Parameters
includeXmlopttrue returns the generated UBL XML for each result. Default false.
Notes
[
{
"companyId": 20,
"documentId": "TEST-0001",
"issueDate": "2026-07-14",
"invoiceTypeCode": "380",
"invoiceTransactionType": "00000000",
"documentCurrencyCode": "AED",
"...": "the rest of a createFull body"
}
]https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/upload/validateValidate Excel — 4-sheet
Parses the 4-sheet bulk-upload workbook and validates every invoice in it without saving anything.
Content-Type: multipart/form-data
Parameters
includeXmlopttrue returns the generated UBL XML per result.
Notes
// multipart/form-data
file: <sample_einvoice_entry.xlsx>https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/upload/simple/validateValidate Excel — 1-sheet
Same as above for the simplified single-sheet workbook.
Content-Type: multipart/form-data
Parameters
includeXmlopttrue returns the generated UBL XML per result.
// multipart/form-data
file: <simple_einvoice_entry.xlsx>7Excel upload
Bulk-create invoices from the Excel template, and get a CSV of what failed.
https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/uploadBulk upload (Excel)
Bulk-creates invoices from the Excel template. Download the template first, then post the filled workbook.
Content-Type: multipart/form-data
Notes
// multipart/form-data
file: <sample_einvoice_entry.xlsx>
companyId: 20https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/upload/templateDownload upload template
Downloads the Excel template. Save the response body as an .xlsx file.
// Binary XLSX stream
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="sample_einvoice_entry.xlsx"https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/upload/errorLogDownload error log (CSV)
Post the results array from an upload response and receive a CSV error log.
Content-Type: application/json
[
{ "invoiceRef": "INV-001", "status": "SUCCESS", "entryId": 1042, "linesCreated": 2, "allowancesCreated": 1, "paymentsCreated": 1 },
{ "invoiceRef": "INV-003", "status": "SKIPPED", "error": "Entry already exists with status SUBMITTED" },
{ "invoiceRef": "INV-004", "status": "FAILED", "error": "[ibr-167-ae] Line 1: vatExemptReasonCode is mandatory when taxCategory is 'E'." }
]8Peppol: own XML and lookup
Send UBL you generated yourself, and check whether a trading partner is reachable on the network.
https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/peppol/create-from-xmlCreate from raw UBL XML
Send UBL you generated yourself. The body is the raw XML document; it is validated exactly as received and sent verbatim.
Content-Type: application/xml
Parameters
companyIdreqYour company id.
environmentoptSANDBOX (default) or LIVE.
saveOnValidationFailureoptfalse (default) means a rejected document is not stored at all; true persists it with its errors.
submitopttrue queues the document for sending immediately.
Notes
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>urn:cen.eu:en16931:2017#conformant#urn:fdc:peppol.eu:2017:poacc:billing:international:ubl:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>XML-2026-0001</cbc:ID>
<cbc:IssueDate>2026-07-14</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
...
</Invoice>https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/peppol/create-from-xml-fileCreate from XML file
The same as above with a multipart file upload instead of a raw body.
Content-Type: multipart/form-data
Parameters
companyIdreqYour company id.
environmentoptSANDBOX (default) or LIVE.
saveOnValidationFailureoptDefault false.
submitopttrue queues the document for sending immediately.
// multipart/form-data
file: <invoice.xml>https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/peppol/lookup/participantsLook up participants (POST)
Check whether trading partners are registered on the Peppol network. Returns the SMP host, the document types they accept and their business card.
Content-Type: application/json
Parameters
environmentoptSANDBOX (default) or LIVE.
Notes
{
"participantIds": [
"0235:1041968874",
"0235:1007116698",
"0235:9900000097"
],
"smlEnvironment": "AUTO"
}https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/peppol/lookup/participantsLook up participants (GET)
The same lookup for GET-style clients, with the ids as a comma-separated query parameter.
Parameters
idsreqComma-separated participant ids, e.g. 0235:1041968874,0235:1007116698. Maximum 50.
environmentoptSANDBOX (default) or LIVE.
smlEnvironmentoptTEST, PRODUCTION or AUTO. Default AUTO.
{
"lookedUpAt": "2026-07-16T12:34:56Z",
"requestedCount": 2,
"registeredCount": 1,
"results": [
{ "participantId": "0235:1041968874", "registered": true },
{ "participantId": "0235:9900000097", "registered": false, "smpError": "SMP service group not found" }
]
}https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/peppol/lookup/participants/{participantId}Look up a single participant
Single-id lookup. URL-encode the id — it contains a colon.
Parameters
participantIdreqe.g. 0235:1041968874 (encoded as 0235%3A1041968874).
environmentoptSANDBOX (default) or LIVE.
smlEnvironmentoptTEST, PRODUCTION or AUTO. Default AUTO.
{
"lookedUpAt": "2026-07-16T12:34:56Z",
"requestedCount": 1,
"registeredCount": 1,
"results": [
{
"participantId": "0235:1041968874",
"registered": true,
"smpHost": "b-3f4a....edelivery.tech.ec.europa.eu",
"smpServiceGroupUrl": "https://b-3f4a.../iso6523-actorid-upis::0235%3A1041968874",
"documentTypes": ["busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"]
}
]
}9Webhooks
Receive pushed status changes and document-ready notifications instead of polling.
https://app.aigentrix.ai/external/api/v1/webhookSubscriptions/eventsGet event catalogue
The event keys your subscription can opt into.
{
"events": [
{ "key": "invoice.status_updated", "description": "Fires when either status or taxStatus changes (one delivery per field), with changedField, previousValue and newValue." },
{ "key": "invoice.document_ready", "description": "Fires when the final PDF and XML documents for an outbound invoice are available." },
{ "key": "invoice.received", "description": "Fires when an inbound Peppol invoice is received and acknowledged for one of your companies." }
]
}https://app.aigentrix.ai/external/api/v1/webhookSubscriptionsCreate subscription
Registers your endpoint. The response contains the signing secret once and only once.
Content-Type: application/json
Notes
{
"companyId": 20,
"environment": "SANDBOX",
"url": "https://your-system.example.com/webhook",
"eventTypes": ["*"],
"description": "Primary integration endpoint"
}https://app.aigentrix.ai/external/api/v1/webhookSubscriptions/{id}/verifyVerify subscription
Sends a webhook.verification POST with a random challenge to your URL. Answer it correctly and the subscription flips to ACTIVE.
Parameters
idreqThe subscription id.
Notes
{
"success": true,
"status": "ACTIVE"
}https://app.aigentrix.ai/external/api/v1/webhookSubscriptions/{id}/testSend test event
Fires a synchronous webhook.test delivery to an ACTIVE subscription — the fastest way to confirm your endpoint is reachable and your signature check passes.
Parameters
idreqThe subscription id.
{
"success": true,
"delivered": true,
"responseCode": 200
}https://app.aigentrix.ai/external/api/v1/webhookSubscriptionsList subscriptions
Lists the SANDBOX and LIVE subscriptions for a company.
Parameters
companyIdreqThe company id.
{
"subscriptions": [
{
"id": 12,
"companyId": 20,
"environment": "SANDBOX",
"url": "https://your-system.example.com/webhook",
"eventTypes": "*",
"status": "ACTIVE"
}
]
}https://app.aigentrix.ai/external/api/v1/webhookSubscriptions/{id}Delete subscription
Permanently deletes a subscription and its delivery history. Deliveries stop immediately.
Parameters
idreqThe subscription id.
{ "success": true }Field reference
Every key accepted by createFull and by the update call, with its PINT business term, whether the rules require it, and the rule id that fires when it is wrong.
Control fields
Not part of the invoice itself — they tell Aigentrix what to do with it.
| JSON field | Term | Required | Notes |
|---|---|---|---|
| companyId | — | Yes | Your company, the seller. Its master record supplies the defaults for the whole seller block. |
| id | — | Update only | The entry id, required on PUT. |
| status | — | Update only | DRAFT or SUBMITTED. Anything else is rejected unless it equals the current status. |
| invoiceRef | — | No | Your own reference key, max 50 characters, returned as-is. |
| validation | — | No | true validates the document before storing it. |
| userField01 … userField10 | — | No | Free text, never sent to Peppol, editable at any status even after delivery. |
| files[] | — | No | Ids of previously uploaded files to embed as supporting documents. |
| sourceType, quickbooksSynced, businessCentralSynced, odooSynced, zohoSynced, apAutomation | — | No | Integration flags, stored only. |
| userId | — | No | Ignored — the acting user comes from the API key. |
Code lists
Taken from the production PINT-AE v1.04 Schematron. A value outside these lists is rejected at validation.
Invoice type codes (IBT-003)
These four are the only codes the ruleset accepts. 383, 386, 388, 389 and 875 are rejected.
| Code | Meaning | Document | Seller TRN |
|---|---|---|---|
| 380 | Commercial invoice — claims payment for goods or services supplied | Invoice | Required |
| 480 | Invoice out of scope of tax — issuer is outside the scope of tax and collects none | Invoice | Must be empty |
| 381 | Credit note — credit information to the relevant party | CreditNote | Required |
| 81 | Credit note related to goods or services — the counterpart of 480 | CreditNote | Must be empty |
Transaction type (BTAE-02)
Eight positions, each 0 or 1. 00000000 is a standard supply. Positions can be combined where the rules allow.
| Position | Pattern | Meaning | What it requires |
|---|---|---|---|
| 1 | 1XXXXXXX | Free trade zone supply | beneficiaryId (ibr-007-ae) |
| 2 | X1XXXXXX | Deemed supply (no consideration) | No payment means (ibr-191-ae); due date optional; not allowed on 480 or 81 |
| 3 | XX1XXXXX | Profit margin scheme | Standard-rate category with extra VAT handling (ibr-116-ae) |
| 4 | XXX1XXXX | Summary invoice | Invoice period start and end (ibr-138-ae) |
| 5 | XXXX1XXX | Continuous supply | — |
| 6 | XXXXX1XX | Agent (disclosed) billing | principalId, different from the seller TRN (ibr-137-ae, ibr-176-ae) |
| 7 | XXXXXX1X | E-commerce supply | Delivery address (ibr-142-ae) |
| 8 | XXXXXXX1 | Export | Buyer TRN optional (ibr-135-ae); delivery address outside the UAE (ibr-152-ae) |
Tax categories (IBT-151)
A 380 or 381 must not consist only of E and O lines (ibr-151-ae).
| Code | Meaning | Rate | Notes |
|---|---|---|---|
| S | Standard rated | 5 | The normal case |
| Z | Zero rated | 0 | Exports and qualifying supplies |
| E | Exempt | 0 | Requires vatExemptReasonCode or text |
| O | Outside the scope of VAT | 0 | The category used on 480 documents |
| AE | Reverse charge | 0 | Requires the buyer TRN, rcmCode and itemStandardId; line tax must be 0 |
One tax breakdown is produced per distinct category and rate — 5 and 5.00 are the same breakdown.
Credit note reason codes (BTAE-03)
Federal Decree-Law 8, Article 61(1). Mandatory on type 381.
| Code | Meaning |
|---|---|
| DL8.61.1.A | Supply cancelled |
| DL8.61.1.B | Nature of the supply changed |
| DL8.61.1.C | Consideration for the supply changed |
| DL8.61.1.D | Goods or services returned |
| DL8.61.1.E | Error in the original tax invoice |
| VD | Voluntary disclosure |
Legal registration types (BTAE-15 / BTAE-16)
| Code | Meaning | Authority field |
|---|---|---|
| TL | Commercial or trade licence | Issuing authority name, mandatory (ibr-172-ae) |
| EID | Emirates ID | — |
| PAS | Passport | Issuing country as an ISO code (ibr-012-ae) |
| CD | Cabinet decision | — |
Reverse-charge goods and services (BTAE-09)
Decree-Law 8, Article 48. Required on every line with tax category AE.
| Code | Meaning |
|---|---|
| DL8.48.3.1 | Crude or refined oil |
| DL8.48.3.2 | Unprocessed or processed natural gas |
| DL8.48.3.3 | Any hydrocarbons |
| DL8.48.8.1 | Electronic devices — phones, computers, tablets |
| DL8.48.8.2 | Pieces and parts of electronic devices |
Payment means (IBT-081)
UNCL 4461. Accepted: 1–68, 70, 74–78, 91–98, ZZZ and Z01–Z08.
| Code | Meaning |
|---|---|
| 10 | In cash |
| 20 | Cheque |
| 30 | Credit transfer |
| 31 | Debit transfer |
| 42 | Payment to bank account |
| 48 | Bank card |
| 49 | Direct debit |
| 54 | Credit card |
| 55 | Debit card |
| 57 | Standing agreement |
| 58 | SEPA credit transfer |
| 59 | SEPA direct debit |
| 68 | Online payment service |
| 97 | Clearing between partners |
| ZZZ | Mutually defined |
Allowance reason codes
UNTDID 5189, used when isCharge is false.
| Code | Meaning |
|---|---|
| 95 | Discount — the usual one |
| 100 | Special rebate |
| 102 | Fixed long-term |
| 103 | Temporary |
| 104 | Standard |
| 105 | Yearly turnover |
| 41 / 42 | Bonus for works ahead of schedule / other bonus |
| 60 | Manufacturer's consumer discount |
| 64 | Special agreement |
| 65 | Production error discount |
| 66 | New outlet discount |
| 67 | Sample discount |
| 68 | End-of-range discount |
| 70 | Incoterm discount |
| 71 | Point-of-sale threshold allowance |
| 88 | Material surcharge or deduction |
Full accepted list: 41 42 60 62 63 64 65 66 67 68 70 71 88 95 100 102 103 104 105.
Charge reason codes
UNTDID 7161, used when isCharge is true. The common ones:
| Code | Meaning |
|---|---|
| DL | Delivery |
| FC | Freight service |
| HD | Handling |
| PC | Packing |
| AA | Advertising |
| AAT | Rush delivery |
| LA | Labelling |
| AEA | Diversion |
| ABK | Miscellaneous |
| ADR | Other services |
| AEM | Clerical |
| FI | Financing |
Full accepted list: AA AAA AAC AAD AAE AAF AAH AAI AAS AAT AAV AAY AAZ ABA ABB ABC ABD ABF ABK ABL ABN ABR ABS ABT ABU ACF ACG ACH ACI ACJ ACK ACL ACM ACS ADC ADE ADJ ADK ADL ADM ADN ADO ADP ADQ ADR ADT ADW ADY ADZ AEA AEB AEC AED AEF AEH AEI AEJ AEK AEL AEM AEN AEO AEP AES AET AEU AEV AEW AEX AEY AEZ AJ AU CA CAB CAD CAE CAF CAI CAJ CAK CAL CAM CAN CAO CAP CAQ CAR CAS CAT CAU CAV CAW CAX CAY CAZ CD CG CS CT DAB DAD DAC DAF DAG DAH DAI DAJ DAK DAL DAM DAN DAO DAP DAQ DL EG EP ER FAA FAB FAC FC FH FI GAA HAA HD HH IAA IAB ID IF IR IS KO L1 LA LAA LAB LF MAE MI ML NAA OA PA PAA PC PL PRV RAB RAC RAD RAF RE RF RH.
UAE country subdivisions (IBT-039 / 054 / 079)
Required whenever the country code is AE. Free text is allowed for other countries.
| Code | Emirate |
|---|---|
| AUH | Abu Dhabi |
| DXB | Dubai |
| SHJ | Sharjah |
| AJM | Ajman |
| UAQ | Umm Al Quwain |
| RAK | Ras Al Khaimah |
| FUJ | Fujairah |
Identifiers
| Identifier | Format | Where it goes |
|---|---|---|
| TRN — VAT registration | 15 digits, starts with 1, ends with 03 | sellerVatTrn, buyerVatTrn (ibr-132-ae) |
| TIN — tax / corporate tax | 10 digits, starts with 1 | sellerOtherId, buyerOtherId (ibr-148-ae) |
| Peppol participant | 0235: followed by the TIN | supplierParticipantId, customerParticipantId |
| Electronic address scheme | 0235 | sellerElectronicAddressSchemeId, buyerElectronicAddressSchemeId |
| FTA special addresses | 0235:9900000097 · 0235:9900000098 · 0235:9900000099 | Deemed supply · buyer not registered · export. Chosen by the server, not by you. |
Common units of measure (IBT-130)
UN/ECE Recommendation 20.
| Code | Meaning |
|---|---|
| EA | Each |
| C62 | One (unit) |
| H87 | Piece |
| HUR | Hour |
| DAY | Day |
| MON | Month |
| ANN | Year |
| KGM | Kilogram |
| MTR | Metre |
| LTR | Litre |
| MTK | Square metre |
| MTQ | Cubic metre |
Calculations and rounding
Every amount is a 2-decimal number and the totals must reconcile within 1 fils. The server rebuilds the line total and the tax breakdown from the lines — the values you send for the other totals must match.
| Rule | Formula |
|---|---|
| ibr-co-10 | lineExtensionTotal = Σ lineNetAmount |
| ibr-co-11 / 12 | docLevelDiscount = Σ document allowances; docLevelCharges = Σ document charges |
| ibr-co-13 | Tax exclusive (IBT-109) = lineExtensionTotal − docLevelDiscount + docLevelCharges |
| ibr-co-14 | taxAmount = Σ over breakdowns of round₂(taxable × rate ÷ 100) |
| ibr-co-15 | totalIncludingTax = IBT-109 + taxAmount |
| ibr-co-16 | payableAmount = totalIncludingTax − prepaidAmount + roundingAmount |
| ibr-147-ae | lineNetAmount = quantity × unitPrice ÷ priceBaseQty + line charges − line allowances |
| ibr-131-ae | Allowance amount = baseAmount × percent ÷ 100 when both are given |
Tax is computed once per breakdown, not per line
This is the single most common reason a document that looks correct in your ERP fails ibr-co-14. With many lines the two figures diverge. On a 76-line invoice the sum of per-line rounded VAT was 2 939.30 while the breakdown VAT on the summed net was 2 939.27 — a 3-fils difference that fails validation.
Send the breakdown figure. If your ERP has to show the other total, put the difference in roundingAmount:
"lineExtensionTotal": 58785.44,
"taxAmount": 2939.27,
"totalIncludingTax": 61724.71,
"roundingAmount": 0.03,
"prepaidAmount": 61724.74,
"payableAmount": 0Line rounding order
Round quantity × price ÷ base to 2 decimals first, then apply the discount or charge, then combine. Rounding at the end instead gives a different answer and fails ibr-147-ae.
Foreign currency
vatInAccountingCurrency = taxAmount × rate and totalInLocalCurrency = totalIncludingTax × rate, both to 2 decimals. The rate itself takes up to 6.
Scenarios
Ten worked cases, each available as a ready body from GET /eInvoiceEntry/examples and as a request in the Postman collection. Only the fields that differ from a standard invoice are listed.
standard-aedStandard VAT invoice to a UAE customer
You are VAT registered and selling inside the UAE.
- •invoiceTypeCode 380, invoiceTransactionType 00000000, currency AED
- •Buyer TRN present, emirate codes on both addresses
- •Lines with taxCategory S at 5%
foreign-currency-usdForeign currency invoice
You invoice in USD, EUR or any non-AED currency.
- •documentCurrencyCode USD and taxCurrencyCode AED
- •exchangeRate, at most 6 decimals
- •vatInAccountingCurrency = taxAmount × rate, totalInLocalCurrency = totalIncludingTax × rate
corporate-tax-only-480Seller registered for corporate tax only
You have a corporate tax registration but no VAT TRN.
- •invoiceTypeCode 480 (or 81 for the credit note)
- •sellerVatTrn empty, sellerOtherId set to the TIN
- •buyerLegalRegistrationId required; lines restricted to categories E, O or Z
credit-note-381Credit note
Goods returned, price reduced, or an error in the original invoice.
- •invoiceTypeCode 381 with a creditNoteReasonCode
- •originalInvoiceReference and its date point at the invoice being credited
- •payments must be an empty array — a credit note carries no payment means
discounts-charges-roundingDiscounts, charges and rounding
You give a line discount, a header discount or add a delivery charge.
- •lineDiscountAmount on the line becomes a line-level allowance
- •Header rows in allowances[] feed docLevelDiscount and docLevelCharges
- •Tax is computed once on the breakdown; the difference goes in roundingAmount
deemed-supplyDeemed supply
Gifts, samples or goods taken for own use — no consideration.
- •invoiceTransactionType 01000000
- •payments empty; the due date becomes optional
- •Routed to the FTA deemed-supply address instead of a customer
buyer-not-on-peppolUAE customer not yet on Peppol
Your customer has a TRN but is not registered on the network.
- •Send the customer's real TRN as normal
- •Leave customerParticipantId empty — the server checks the network and routes automatically
- •The document is still reported to the FTA and delivered to the not-registered address
exportExport
Your customer is abroad.
- •invoiceTransactionType 00000001
- •Foreign buyer without a TRN or TIN; free-text country subdivision
- •Lines zero-rated (Z); delivery address line 1, city and subdivision are mandatory
reverse-chargeReverse charge
Oil, gas, hydrocarbons or electronic devices to a VAT-registered business.
- •Lines use taxCategory AE with taxRatePercent 0 and lineTaxAmount 0
- •Each line carries an rcmCode and an itemStandardId (GTIN)
- •The buyer TRN is mandatory
free-trade-zoneFree trade zone
Supply inside a designated free zone.
- •invoiceTransactionType 10000000
- •beneficiaryId identifies the party receiving the goods in the zone
Validation rules and how to fix them
GET /eInvoiceEntry/{entryId}/validationErrors returns rule ids. These are the ones you will actually meet.
| Rule | What it means | How to fix it |
|---|---|---|
| ibr-134-ae | Seller VAT identifier missing | Provide sellerVatTrn, or switch to type 480 / 81 with sellerOtherId. |
| ibr-132-ae | VAT identifier is not a valid TRN | 15 digits, starts with 1, ends with 03. Check for trailing spaces. |
| ibr-148-ae | TIN format wrong | 10 digits starting with 1. |
| ibr-177-ae | Neither TRN nor TIN given | Provide one of them. |
| ibr-150-ae / 181-ae / 172-ae | Seller legal registration id, type or authority missing | Fill the trade licence number, set the type to TL and give the issuing authority — usually in the company master. |
| ibr-143-ae / 144-ae | Seller or buyer address incomplete | Address line 1, city and country subdivision are all required. |
| ibr-128-ae | Subdivision is not an emirate code | Use AUH, DXB, SHJ, AJM, UAQ, RAK or FUJ for AE addresses. |
| ibr-135-ae / 149-ae | Buyer has no identifier | Give the buyer TRN, or the TIN, or a legal registration id. |
| ibr-136-ae | Buyer legal registration id missing on 480 / 81 | Set buyerLegalRegistrationId. |
| ibr-122-ae | Tax category not E, O or Z on 480 / 81 | Change the line categories. |
| ibr-151-ae | A 380 / 381 made up only of E and O lines | Use type 480 / 81 instead, or add taxable lines. |
| ibr-158-ae / 001-ae | Credit note reason missing or not in the list | Set creditNoteReasonCode from the FTA list. |
| ibr-191-ae | Payment means on a credit note or deemed supply, or missing on an invoice | Remove or add the payments array accordingly. |
| ibr-127-ae | Due date missing | Set paymentDueDate whenever the amount due is greater than zero. |
| ibr-141-ae | Tax point date is not before the issue date | Remove or correct taxPointDate. |
| ibr-159-ae / 002-ae / 140-ae / 175-ae / 153-ae | Foreign currency fields wrong | exchangeRate (≤ 6 decimals), taxCurrencyCode AED, and both AED restatement totals. |
| ibr-co-10 … co-16 | Totals do not reconcile | See the Calculations section — most often tax computed per line instead of per breakdown. |
| ibr-147-ae | Line net ≠ quantity × price ± allowances | Recompute lineNetAmount. Line discounts must actually be sent, not just netted off. |
| ibr-131-ae | Allowance amount ≠ base × percent | Fix the numbers, or drop baseAmount and percent and send only amount. |
| aligned-ibrp-s-06 | Tax category on a line-level allowance | Line-level allowance rows carry no tax category — remove it. |
| ibr-103-ae / 162-ae / 166-ae / 174-ae / 006-ae | Reverse charge incomplete | Buyer TRN, line tax 0, an rcmCode, and an itemStandardId on every AE line. |
| ibr-007-ae / 137-ae / 176-ae | Beneficiary or principal id | beneficiaryId for a free zone supply; principalId for agent billing, and it must differ from the seller TRN. |
| ibr-152-ae / 142-ae | Delivery address missing | Line 1, city and subdivision for exports and e-commerce. |
| ibr-138-ae | Summary invoice without a period | Set invoicePeriodStartDate and invoicePeriodEndDate. |
| ibr-157-ae | Deemed, summary or margin flag on a 480 / 81 | Change either the transaction type or the invoice type. |
Submitting your own UBL XML
If you already generate compliant UBL, send it as-is. Aigentrix validates it, wraps it in a transport envelope and delivers it without touching the document.
Use POST /eInvoiceEntry/peppol/create-from-xml with a raw application/xml body, or the multipart /create-from-xml-file variant.
- •The document is validated against XSD and the PINT-AE Schematron exactly as received.
- •It is then kept verbatim and sent exactly as received inside a fresh transport envelope — nothing is defaulted, reordered or reformatted.
- •It appears in the entry's Files tab and in GET /eInvoiceEntry/{id} as originalXml, with submittedAsXml: true.
- •If the entry is later edited through the API or the screen, the stored fields become the source of truth, the document is regenerated from them, and submittedAsXml turns false.
- •The envelope identifiers — sender, receiver, instance id — are ours. A cbc:UUID inside your document is left untouched.
- •saveOnValidationFailure=false (the default) means a rejected document is not stored at all.
Supporting documents
An invoice can carry informative supporting documents — work reports, certificates, delivery notes, drawings. They travel inside the invoice as base64 with a mime code and a file name.
How it works
- •Every file in the entry's Files tab is embedded in the outgoing document. There is no per-file toggle — remove a file to keep it out.
- •If a file cannot be fetched at send time the dispatch fails and is retried. An invoice is never sent silently without a document the user attached.
- •Received documents keep their original file name and mime code, can be previewed and downloaded, and cannot be deleted from an inbound entry.
- •A copy of the invoice itself as a PDF is explicitly not an attachment.
Allowed mime codes
| Type | Mime code |
|---|---|
| application/pdf | |
| PNG | image/png |
| JPEG | image/jpeg |
| CSV | text/csv |
| XLSX | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
| ODS | application/vnd.oasis.opendocument.spreadsheet |
| XML | application/xml |
Any other file type is refused in the Files tab (rule ibr-cl-24).
Updating, locking and user fields
PUT /eInvoiceEntry/{entryId} takes the same body shape as createFull, plus id. What it is allowed to change depends on where the entry has got to.
| Entry status | What the update may change |
|---|---|
| DRAFT, VALIDATION_FAILED, REJECTED, TRANSMISSION_FAILED | Everything. Sending "status": "SUBMITTED" submits the document. |
| SUBMITTED, PROCESSING, VALIDATION_PASSED, SENDING, DELIVERED, ACKNOWLEDGED, … | Only userField01 … userField10. Every other field, the status and the tax status stay as they are; the call returns success: true with the unchanged status and a note saying only user fields were updated. |
Tag a delivered invoice with an ERP reference
User fields are free text, are never sent to Peppol, and can be written at any status — which makes them the right place for your own cross-references.
curl -X PUT "https://app.aigentrix.ai/external/api/v1/eInvoiceEntry/45426" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $AIGENTRIX_API_KEY" \
-d '{ "id": 45426, "userField01": "PO-REF-2026-0917" }'Deleting an entry (DELETE /eInvoiceEntry with { "ids": [45426] }) is only possible for the editable statuses above.
Webhooks
Rather than polling for status, register an endpoint and Aigentrix will push each change to you. Three setup calls, then you are done.
Setup
- 1POST /webhookSubscriptions with your URL and the events you want. Save the secret from the response — it is shown once.
- 2POST /webhookSubscriptions/{id}/verify. Aigentrix sends a challenge; answer it correctly and the subscription goes ACTIVE.
- 3POST /webhookSubscriptions/{id}/test to confirm your endpoint is reachable and your signature check passes.
Events
| Event | When it fires |
|---|---|
| invoice.status_updated | Either status or taxStatus changed — one delivery per field, carrying changedField, previousValue and newValue. |
| invoice.document_ready | The final PDF and XML documents for an outbound invoice are available. |
| invoice.received | An inbound Peppol invoice was received and acknowledged for one of your companies. |
| webhook.verification | The handshake challenge sent by the verify call. |
| webhook.test | A synthetic payload sent by the test call. |
Verifying the signature
Every delivery carries these headers. Recompute the HMAC over timestamp + "." + rawBody and compare — never trust an unverified payload.
X-Aigentrix-Signature: t=1785789230,v1=<hex hmacSHA256(secret, t + "." + body)>
X-Aigentrix-Event-Id: ce484636-ab29-447a-be57-a4d4d8230779
X-Aigentrix-Environment: SANDBOXThe verification handshake expects a 2xx response with both the echoed challenge and its signature:
import crypto from "node:crypto";
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("X-Aigentrix-Signature") ?? "";
const t = header.match(/t=([^,]+)/)?.[1];
const v1 = header.match(/v1=([^,]+)/)?.[1];
const expected = crypto
.createHmac("sha256", process.env.AIGENTRIX_WEBHOOK_SECRET)
.update(t + "." + req.body.toString("utf8"))
.digest("hex");
if (!v1 || !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) {
return res.status(401).end();
}
const event = JSON.parse(req.body.toString("utf8"));
// The verification handshake must echo the challenge AND sign it.
if (event.eventType === "webhook.verification") {
const challenge = event.data.challenge;
return res.json({
challenge,
signature: crypto
.createHmac("sha256", process.env.AIGENTRIX_WEBHOOK_SECRET)
.update(challenge)
.digest("hex"),
});
}
// Handle the real events here.
res.status(200).end();
});Example payload
An outbound invoice reaching ACKNOWLEDGED. Failure states — REJECTED, VALIDATION_FAILED, TRANSMISSION_FAILED — carry rejectionReason instead of documents.
{
"eventId": "ce484636-ab29-447a-be57-a4d4d8230779",
"eventType": "invoice.status_updated",
"environment": "SANDBOX",
"occurredAt": "2026-08-03T20:33:49Z",
"entryId": 40117,
"invoiceNumber": "RTRUC-650020",
"companyId": 20,
"organisationId": 27,
"type": "OUTBOUND",
"changedField": "status",
"previousValue": "DELIVERED",
"newValue": "ACKNOWLEDGED",
"documents": [
{ "type": "PDF", "fileName": "outbound_sent", "url": "https://app.aigentrix.ai/external/api/v1/print/xml/40117?fileName=outbound_sent" },
{ "type": "XML", "fileName": "outbound_sent", "url": "https://app.aigentrix.ai/external/api/v1/print/orgxml/40117?fileName=outbound_sent" },
{ "type": "PDF", "fileName": "outbound_ack", "url": "https://app.aigentrix.ai/external/api/v1/print/xml/40117?fileName=outbound_ack" },
{ "type": "XML", "fileName": "outbound_ack", "url": "https://app.aigentrix.ai/external/api/v1/print/orgxml/40117?fileName=outbound_ack" }
]
}Errors
A business error arrives with HTTP 200 and success: false — always check the flag, not just the status code.
HTTP status codes
| HTTP | Body | Meaning |
|---|---|---|
| 200 | success: false with errorKey or errorLog | A business error — the request was understood but refused. |
| 400 | error | Malformed request, or an invalid environment value. |
| 401 | — | Missing, invalid or revoked API key. |
| 403 | errorKey: "Access denied" | The entry belongs to another organisation. |
| 500 | error | Unexpected. Contact support with the entryId or documentId. |
Common errorKey values
| errorKey | Meaning |
|---|---|
| company.not.found | No company with that id. |
| company.not.accessible | The company exists but belongs to a different organisation. |
| organisation.not.found | The API key does not resolve to an organisation. |
| document.plan.missing | The company has no e-invoicing plan. |
| document.limit.exist | The plan's document limit has been reached. |
| file.original_xml.protected | The original XML of an XML-submitted invoice cannot be deleted. |
| Only DRAFT or SUBMITTED status is allowed. | You asked for a status that cannot be set through the API. |