Getting started with the AXS API
Submit a standard UAE tax invoice with a machine credential, interpret the response, and retrieve its current status. Run the commands in order in one Bash session. Use an agreed test environment and test participants for this exercise. The sample contains fictional trading details; replace all business and tax data before using it for a real transaction.
Service boundary and corrections
AXS accepts the UAE electronic-invoicing categories: tax/commercial invoices and credit notes, including the two self-billed tax categories. Your company or ERP decides tax treatment, the actual supply date and correction grounds. A validation pass checks the submitted data; it does not prove the transaction facts. Contracts, certified milestones, the general ledger and bank reconciliation stay in your ERP. The continuous-supply one-year limit runs from actual supply, not a contract anniversary.
Issue B2C/simplified receipts through your ERP or point-of-sale system under the VAT rules applicable outside electronic invoicing. Pro forma documents and quotations belong to your sales workflow; creating one does not itself establish a tax point. None of these is an AXS electronic-invoice category.
Old FTA administrative exceptions for invoice/credit-note content or issuance expire when electronic invoicing becomes mandatory for the person (VATGEX1 §4.5; VAT Executive Regulation Articles 59(16)/60(8)). There is no legacy-exception switch. A genuine draft may be replaced; an admitted document remains preserved.
Document details expose invalidatedBy: derived workflow links to admitted credit
notes, with one explicit preceding-invoice reference, matching parties, billing
mode and currency, and the full positive gross amount. Partial credits are not
summed, and combined references are not allocated to an original. The indicator
does not change any processing state or assert delivery/FTA acceptance. Refresh
the original detail after a correction. More than 100 candidates are not assessed;
an empty list does not prove there are no corrections outside this matching rule.
The official PINT-AE CreditReason code list names VD Volume Discount., not void.
VD alone never invalidates an invoice; even a legacy explicit reference must still
meet the full-gross comparison. Current rule ibr-055-ae prohibits a VD credit note
from having a preceding reference, so an unreferenced VD cannot be linked
automatically. Validation stays intact; the source overrides the earlier VD/void premise.
English suffices for the commercial view. FTA submission is subject to Tax Procedures Law Article 5 and its Executive Regulation Article 5: the FTA may accept English and may request an Arabic translation approved under UAE translation law, by its specified deadline. The English/Arabic PDF view does not certify that translation; your company remains responsible. Downloading a PDF is obtaining a view, not an AXS issuance event. Sector-specific hosting/localisation duties must be agreed separately in the customer contract and checked against the residency policy.
Before you start
Ask your AXS contact for the following handover. A token alone is insufficient.
- An onboarded tenant ID and a participant registered uniquely to that tenant.
For this standard invoice the issuing participant is the seller. For
self-billing it is the buyer;
SELLER_NOT_REGISTEREDremains the error code, withbuyer.endpointidentifying that case. - An ACTIVE machine client with purpose
erp-ingest, its client ID and its one-time secret, delivered through an approved secure channel. Store the secret in your secret manager. Do not put it in source control, tickets, screenshots, browser storage or logs. - The exact API base URL, token URL, expected issuer and API audience, plus the tenant and permitted scope. These are environment parameters, not values to infer from another deployment.
- The test seller/buyer TINs and TRNs, and confirmation that the test receiver is
appropriate. The
0235endpoint value is the 10-digit TIN, not the 15-digit VAT TRN. The TRN must agree with that party's TIN. - Bash, curl, jq and uuidgen. Download the
sample invoice and keep its absolute
filename. In a repository checkout this is
examples/ingest/valid-invoice.json.
Creation of tenants and participant onboarding are operator responsibilities. A tenant administrator manages machine clients in AXS eInvoice's API-client screen — Manage → API clients, which the Get credentials in AXS eInvoice button in this page's header opens directly when the portal address is configured for this deployment. An ERP credential cannot create, rotate or revoke other credentials. If provisioning is unavailable, AXS must complete the handover before you start; a stub-generated secret is not a usable Keycloak credential.
Environment and authentication
Set these non-secret parameters from your handover before running the code:
| Variable | Value to supply |
|---|---|
API_BASE_URL |
Tenant API URL, including any deployment base path, without trailing / |
TOKEN_URL |
Exact token endpoint: <issuer>/protocol/openid-connect/token; preserve any /auth prefix |
CLIENT_ID |
Your confidential machine client ID |
TENANT_ID |
The tenant bound to that client |
SELLER_TIN, SELLER_TRN |
Your registered test issuer's TIN and TRN |
BUYER_TIN, BUYER_TRN |
Agreed test receiver's TIN and TRN |
SAMPLE_FILE |
Absolute local path to the downloaded sample JSON |
Use HTTPS on deployed environments. Loopback HTTP is only for local testing.
The API verifies the JWT's RS256 signature, issuer, audience and expiry.
The client's audience mapper must include the API audience supplied by AXS
(the API's KEYCLOAK_CLIENT_ID), which need not equal your machine CLIENT_ID.
Sending an audience parameter yourself does not configure that mapper.
A machine token has axs_principal_kind: machine, azp: <CLIENT_ID>, a single
tenant: <TENANT_ID> and the space-separated scope axs:ingest. The four
submission/status routes below all require that scope and tenant
entitlement. Requesting a scope cannot grant one the client was not assigned.
x-tenant-id selects the tenant; it never grants access to another tenant.
GET /info is a public issuer/realm diagnostic, not a credential service or a
complete audience/provisioning handover.
The following requests client_credentials. The secret is read without echo;
it is sent to curl through standard input, not as a process argument. Tokens
and headers are held in a private temporary directory. Keep shell tracing off.
set -euo pipefail
set +x
: "${API_BASE_URL:?}" "${TOKEN_URL:?}" "${CLIENT_ID:?}" "${TENANT_ID:?}"
: "${SELLER_TIN:?}" "${SELLER_TRN:?}" "${BUYER_TIN:?}" "${BUYER_TRN:?}"
: "${SAMPLE_FILE:?}"
umask 077
WORK_DIR="$(mktemp -d)"
trap 'rm -f "$WORK_DIR/token.json" "$WORK_DIR/headers"' EXIT
printf 'Private working directory: %s\n' "$WORK_DIR"
cp "$SAMPLE_FILE" "$WORK_DIR/template.json"
if [ -z "${CLIENT_SECRET:-}" ]; then
read -r -s -p 'Machine client secret: ' CLIENT_SECRET
printf '\n'
fi
printf '%s' "$CLIENT_SECRET" | curl --silent --show-error --fail-with-body \
"$TOKEN_URL" -H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode 'scope=axs:ingest' \
--data-urlencode 'client_secret@-' > "$WORK_DIR/token.json"
unset CLIENT_SECRET
jq -er '.access_token | select(type == "string" and length > 0)' \
"$WORK_DIR/token.json" | while IFS= read -r token; do
printf 'Authorization: Bearer %s\nx-tenant-id: %s\n' "$token" "$TENANT_ID"
done > "$WORK_DIR/headers"
curl --silent --show-error --fail-with-body "$API_BASE_URL/me" \
-H @"$WORK_DIR/headers" > "$WORK_DIR/me.json"
jq -e --arg tenant "$TENANT_ID" \
'.kind == "machine" and .tenantId == $tenant and (.scopes | index("axs:ingest") != null)' \
"$WORK_DIR/me.json"
/me must return HTTP 200 and the assertion prints true. A token response
contains access_token, token_type and expires_in; do not print the token.
Cache it only for its lifetime, renew shortly before expiry, and use a fresh
client-credentials request when needed. This flow does not depend on a refresh
token. Rebuild the header file after renewal. On shell exit the credential files are
removed, while invoice and result files remain in the printed private directory.
Keep those files and IDs for retries/reconciliation, then remove the directory
when no longer needed. Do not rerun document preparation to retry an existing
transaction: reuse its saved JSON. Do not enable automatic POST retries with
a freshly generated ID.
First synchronous invoice
Prepare one document, then keep its ID, UUID and content unchanged for retries. A new transaction needs both a new invoice ID and UUID. The fixed identifiers and July dates in the downloaded template are replaced below. All SBDH and party endpoint values remain aligned.
DOC_UUID="$(uuidgen | tr '[:upper:]' '[:lower:]')"
DOC_ID="AXS-FIRST-$DOC_UUID"
ISSUE_DATE="$(date -u +%F)"
jq --arg id "$DOC_ID" --arg uuid "$DOC_UUID" --arg day "$ISSUE_DATE" \
--arg seller "$SELLER_TIN" --arg sellerTrn "$SELLER_TRN" \
--arg buyer "$BUYER_TIN" --arg buyerTrn "$BUYER_TRN" \
'.invoice.id=$id | .invoice.uuid=$uuid | .invoice.issueDate=$day |
.invoice.paymentDueDate=$day |
.sbdh.sender=("0235:"+$seller) | .sbdh.receiver=("0235:"+$buyer) |
.invoice.seller.endpoint.value=$seller | .invoice.seller.taxRegistrationId=$sellerTrn |
.invoice.buyer.endpoint.value=$buyer | .invoice.buyer.taxRegistrationId=$buyerTrn' \
"$WORK_DIR/template.json" > "$WORK_DIR/invoice.json"
HTTP="$(curl --silent --show-error -o "$WORK_DIR/sync.json" -w '%{http_code}' \
"$API_BASE_URL/ingest" -H @"$WORK_DIR/headers" \
-H 'Content-Type: application/json' --data-binary @"$WORK_DIR/invoice.json")"
printf 'Sync HTTP %s\n' "$HTTP"
jq . "$WORK_DIR/sync.json"
case "$HTTP" in 200|201) ;; *) exit 1 ;; esac
INTEGRATION_ID="$(jq -er '.integrationId' "$WORK_DIR/sync.json")"
DOCUMENT_PATH="$(jq -rn --arg id "$INTEGRATION_ID" '$id|@uri')"
curl --silent --show-error --fail-with-body \
"$API_BASE_URL/documents/$DOCUMENT_PATH" -H @"$WORK_DIR/headers" \
> "$WORK_DIR/document.json"
jq . "$WORK_DIR/document.json"
A first admission returns 201; an identical replay returns 200 with
created: false. Example response (IDs vary):
{"integrationId":"AXS-FIRST-<uuid>","outcome":"partial","created":true,"routeClass":"normal","rulePackId":"draft-uae-route-class-2026-10@provisional"}
Admission validates the canonical envelope, structural and endpoint rules,
issuer registration, and the installed PINT-AE XSD/Schematron pack. It records
TRANSPORT/PENDING (a document to a predefined buyer address starts on
C5_C2/PENDING instead — see
Predefined buyer addresses (report-only)). 201 is not a delivery receipt. outcome describes the
currently recorded legs: partial while pending, failed if a leg failed,
compliant if every present leg succeeded. It can change later and does not
prove that every externally required receipt has arrived. rulePackId here is
the route-classification stamp, not the version of the PINT-AE validation pack.
The document response contains integrationId, legs, routeClass,
rulePackId, direction, header, dispatch and artifact. For example,
its initial legs array is:
[{"leg":"TRANSPORT","state":"PENDING","rank":0,"reopenEpoch":0,"appliedReopenIds":[]}]
Read each leg and the dispatch/receipt fields to follow progress. artifact.stored
means that an artifact is stored, not that the receiver accepted it. The detail
response does not currently contain an aggregate outcome field.
For an unknown document ID, or a document owned by another tenant, this endpoint
returns 404 with the standard error envelope (statusCode, message, requestId), the
same contract as /documents/{id}/invoice, /ubl and /pdf.
Asynchronous submission and polling
Use a second ID and UUID for this second transaction. The server returns 202 after accepting the job. Validation occurs in the worker. A parseable but invalid invoice can therefore receive 202. Malformed JSON and authentication errors can still be rejected on the HTTP request path.
ASYNC_UUID="$(uuidgen | tr '[:upper:]' '[:lower:]')"
jq --arg id "AXS-ASYNC-$ASYNC_UUID" --arg uuid "$ASYNC_UUID" \
'.invoice.id=$id | .invoice.uuid=$uuid' "$WORK_DIR/invoice.json" \
> "$WORK_DIR/async-invoice.json"
HTTP="$(curl --silent --show-error -o "$WORK_DIR/accepted.json" -w '%{http_code}' \
"$API_BASE_URL/ingest/async" -H @"$WORK_DIR/headers" \
-H 'Content-Type: application/json' --data-binary @"$WORK_DIR/async-invoice.json")"
printf 'Async HTTP %s\n' "$HTTP"
jq . "$WORK_DIR/accepted.json"
[ "$HTTP" = 202 ]
MESSAGE_ID="$(jq -er '.messageId' "$WORK_DIR/accepted.json")"
STATUS_PATH="$(jq -er '.statusUrl' "$WORK_DIR/accepted.json")"
[ "$STATUS_PATH" = "/ingest/$MESSAGE_ID" ]
for attempt in $(seq 1 30); do
curl --silent --show-error --fail-with-body "$API_BASE_URL$STATUS_PATH" \
-H @"$WORK_DIR/headers" > "$WORK_DIR/job.json"
STATUS="$(jq -er '.status' "$WORK_DIR/job.json")"
case "$STATUS" in
done|invalid|failed) break ;;
queued|processing) sleep 2 ;;
*) printf 'Unexpected status: %s\n' "$STATUS"; exit 1 ;;
esac
done
jq . "$WORK_DIR/job.json"
[ "$STATUS" = done ]
jq -e '.result.kind == "created" or .result.kind == "duplicate"' "$WORK_DIR/job.json"
ASYNC_PATH="$(jq -er '.integrationId | @uri' "$WORK_DIR/job.json")"
curl --silent --show-error --fail-with-body "$API_BASE_URL/documents/$ASYNC_PATH" \
-H @"$WORK_DIR/headers" > "$WORK_DIR/async-document.json"
jq . "$WORK_DIR/async-document.json"
The loop is bounded to about one minute. A timeout means unresolved; retain
the messageId and continue polling later, with a fresh token if needed. Do not
create another invoice to hide a timeout. Unknown message IDs return 404 for the
selected tenant. Example completed job, with a shortened placeholder message ID:
{"messageId":"<64 hex characters>","status":"done","integrationId":"AXS-ASYNC-<uuid>","result":{"kind":"created","outcome":"partial","routeClass":"normal","rulePackId":"draft-uae-route-class-2026-10@provisional"},"error":null}
| Job status | What to do |
|---|---|
queued, processing |
Keep polling within your retry budget. |
done, result.kind: created or duplicate |
Read integrationId, then the document status. This is an ingest result, not final compliance or delivery. |
done, result.kind: conflict |
Same business-ID conflict as synchronous 409. result is exactly {"kind":"conflict"}; do not count it as a successful new invoice. |
invalid |
Terminal validation rejection. result.violations has the synchronous 422 list; integrationId is null. Correct the input/registration before resubmitting. |
failed |
Infrastructure retries exhausted; error carries the reason. Give support the message ID; identical resubmission does not restart it (an operator retry does). |
One-call file submission
If your ERP already exports UBL 2.1 or the portal CSV layout, POST /ingest/file
takes the whole file in one request: the same token, axs:ingest scope and
x-tenant-id header as POST /ingest, with the file as the raw body.
POST /ingest/file
Authorization: Bearer <access token>
x-tenant-id: <tenant id>
Content-Type: application/xml (one UBL invoice) or text/csv (many invoices)
<the file bytes>
The file is malware-scanned first. Every invoice in it then goes through the
same ingest path as POST /ingest — envelope, structure, issuer
registration, UUID uniqueness and the full PINT-AE rule pack — in file order.
A CSV file uses the tenant company profile as the seller, exactly like the
portal upload; without a profile the whole file is rejected. The answer is
200 with one result per invoice:
{"summary":{"total":2,"created":1,"duplicate":0,"conflict":0,"invalid":1},"items":[{"index":0,"sourceRef":{"kind":"csv-rows","from":2,"to":2},"invoiceId":"INV-1","kind":"created","integrationId":"INV-1","outcome":"partial","routeClass":"normal","rulePackId":"draft-uae-route-class-2026-10@provisional","violations":[],"warnings":[],"report":{"rulePackId":"pint-ae-1.0.4","valid":true,"layers":[],"findings":[]}},{"index":1,"sourceRef":{"kind":"csv-rows","from":3,"to":3},"invoiceId":"INV-2","kind":"invalid","violations":[{"rule":"CSV_ROW","path":"issue_date","message":"<reason>"}],"warnings":[]}]}
items[].kind |
Meaning |
|---|---|
created |
Admitted now — the same as a synchronous 201. Follow it with GET /documents/{integrationId}. |
duplicate |
The identical invoice was already admitted (synchronous 200). |
conflict |
Same tenant + invoice ID, different content (synchronous 409). Investigate; never change the ID to bypass it. |
invalid |
Rejected, nothing stored. Read every violations[] entry. |
report is the PINT-AE validation report of that submission, including
Schematron warnings on an accepted invoice; it is absent when the invoice
was rejected before the rule pack ran. Idempotency uses the same key as
POST /ingest — tenant + invoice ID + content — so re-sending the identical
file after a timeout or 5xx is safe: invoices already admitted come back as
duplicate. There is no separate idempotency header. A CSV invoice's UUID is
derived from its cell values, so the same rows give the same UUID; changing a
value of an invoice that was already admitted is a conflict.
A 422 with violations means the file itself was refused and no invoice
was processed: FILE_CONTENT_TYPE (send application/xml, text/xml or
text/csv), FILE_MALWARE, FILE_PARSE, FILE_ITEM_LIMIT (too many invoices
in one file) or SELLER_PROFILE_MISSING (CSV without a company profile). A
413 means the body exceeds the request size limit, a 503 that the malware
scanner gave no verdict; split or retry the file accordingly.
Errors and retry decisions
| HTTP status | Meaning and action |
|---|---|
| 200 / 201 | Sync duplicate / new admission respectively. For GET, inspect the response content. |
| 202 | Async acceptance only; poll and inspect status and result.kind. |
| 400 | Malformed request or missing/invalid x-tenant-id (after authentication). |
| 401 | Missing, invalid or expired bearer; also wrong signature, issuer or audience. Renew once with correct configuration. |
| 403 | Token is valid but tenant entitlement or machine axs:ingest scope is missing. Fix the handover; retrying unchanged cannot grant access. |
| 409 | Same tenant + invoice ID, different canonical invoice. Investigate the prior submission; never silently overwrite or change the ID to bypass it. |
| 413 | Request body larger than the configured limit (for example a large /ingest/file upload). Split the file; resending it unchanged fails again. |
| 415 | Unsupported Content-Type for the route. Send JSON to /ingest, and application/xml, text/xml or text/csv to /ingest/file. |
| 422 | Envelope, structural, registration, UUID uniqueness or PINT-AE validation rejection. Read every rule, path, message. |
| 429 | Rate limited; honor Retry-After when supplied and back off. |
| 5xx / network timeout | Outcome may be unknown. Query known IDs and retry identical input with bounded exponential backoff and jitter. Escalate persistent failure. |
The actual response shapes differ. 401/403 and other thrown HTTP errors use an envelope like this (request ID, time and path vary):
{"statusCode":401,"error":"Unauthorized","message":"missing bearer token","requestId":"<request-id>","path":"/ingest","timestamp":"<ISO timestamp>"}
403 uses error: "Forbidden" and message: "principal is not entitled to this tenant"
or "missing required scope: axs:ingest". An invalid bearer uses
message: "invalid token". Keep requestId / x-request-id for support, without
sending your Authorization header or secret. The 409 and 422 bodies are instead:
{"error":"document already ingested with different content","integrationId":"AXS-FIRST-<uuid>"}
{"violations":[{"rule":"SELLER_NOT_REGISTERED","path":"seller.endpoint","message":"issuing participant 0235:1995999999 is not registered to the submitting tenant; the tenant is registered as 0235:1000000777","detail":{"issuerParticipantId":"0235:1995999999","registeredParticipantIds":["0235:1000000777"]}}]}
SELLER_NOT_REGISTERED keeps its code. When your tenant already owns registered
participants, just not the one the invoice names, the violation also carries a
detail object (issuerParticipantId and your registeredParticipantIds) and the
message names both — usually a seller TRN that does not match your registration.
A tenant with no participant at all gets the short message and no detail.
path from AXS's own rules is a dotted path rooted at the canonical invoice,
without an invoice. prefix — seller.name, uuid, lines[0].itemName,
seller.endpoint. Parts of the request envelope that are not the invoice keep
their own root, so an SBDH finding reads sbdh.sender. A finding that names no
single field carries an empty string. PINT-AE rule-pack findings are the
documented exception: they use a Schematron rule ID (for example ibr-132-ae)
and an XPath location. Fatal/error findings reject; warnings alone do not. Do
not build a parser that assumes every path is a dot-separated JSON field.
The same violations body answers a rejected query parameter, with the
parameter name as path: GET /peppol/verify returns 422
{"violations":[{"rule":"INVALID_TRN","path":"trn","message":"trn must be exactly 15 digits"}]}
when trn is missing, repeated or not exactly 15 digits, and never asks the Peppol
network.
Every message is informational English text for logs and developers — branch
and localise on the stable rule code, never on the wording. The master-data saves
(POST/PUT /partners, POST/PUT /products, PUT /profile) answer with the same
body, the body field as path, for example
{"violations":[{"rule":"MANDATORY_FIELD","path":"name","message":"name is required"},{"rule":"INVALID_TRN","path":"trn","message":"trn must be exactly 15 digits"}]}.
Exercise replay, conflict and rejection on the same test invoice:
for variant in replay conflict invalid; do
case "$variant" in
replay) cp "$WORK_DIR/invoice.json" "$WORK_DIR/check.json"; EXPECTED=200 ;;
conflict) jq '.invoice.lines[0].itemName="Changed widget"' \
"$WORK_DIR/invoice.json" > "$WORK_DIR/check.json"; EXPECTED=409 ;;
invalid) jq '.invoice.id=""' "$WORK_DIR/invoice.json" \
> "$WORK_DIR/check.json"; EXPECTED=422 ;;
esac
HTTP="$(curl --silent --show-error -o "$WORK_DIR/check-result.json" -w '%{http_code}' \
"$API_BASE_URL/ingest" -H @"$WORK_DIR/headers" \
-H 'Content-Type: application/json' --data-binary @"$WORK_DIR/check.json")"
printf '%s: HTTP %s (expected %s)\n' "$variant" "$HTTP" "$EXPECTED"
jq . "$WORK_DIR/check-result.json"
[ "$HTTP" = "$EXPECTED" ]
done
Synchronous idempotency is keyed by (tenant, invoice.id) and hashes the
parsed canonical invoice, with recursively sorted object keys. Formatting
and object-key order do not create a new invoice; arrays and field values still
matter. SBDH is validated but is not part of that content hash. Validation runs
before duplicate detection, so a retry may reject if registration or rules have
changed. A UUID reused by a different invoice ID in the same tenant yields
422 UUID_NOT_UNIQUE, not 409. There is no caller-supplied Idempotency-Key
header in this implementation.
Your ERP numbers its own invoices: invoice.id is sent as you assign it. The
portal's invoice number series (ADR-0230) apply only to invoices a person issues
by hand in the portal; the ingest body's optional numberSeries field is refused
with 422 NUMBER_SERIES_PORTAL_ONLY for machine clients, so omit it. A
series skips any number your ERP has already used in the tenant, so the two
numbering sources never produce the same invoice.id.
Async message IDs hash (tenant, complete parsed request body), including
SBDH, with stable object-key order. Identical resubmission returns the same
message ID and never creates a second job or a second processing run. A 202
means the submission, including its body, is durably stored with the job: if
queue delivery failed, the platform re-queues a job that stays queued
automatically, within minutes. An identical resubmission of a queued job also
re-queues it immediately. A resubmission does not restart an invalid or
failed job. For failed, give support the message ID; operators can retry it.
A changed body produces a new job, but that job still meets the synchronous
business-ID/UUID rules. Retry budgets and recovery are not an exactly-once
delivery guarantee.
Predefined buyer addresses (report-only)
When the buyer's electronic address (IBT-049) is one of the three predefined addresses of the OpenPeppol PINT-AE BIS (§1.5.3 "Predefined endpoint"), the document is not sent over the Peppol network — there is no C3 to receive it. AXS only reports it to the FTA (C5):
| Buyer address | Use |
|---|---|
0235:9900000097 |
deemed supply |
0235:9900000098 |
the buyer is not yet in scope of e-invoicing |
0235:9900000099 |
export to a buyer that is not on Peppol |
The address decides, not the route class: an export to a buyer that has a real
Peppol ID is sent as usual, and a document classified export but addressed
to 0235:9900000097 is still report-only. The route class (routeClass) is a
label and does not change.
What you see on such a document:
- the first leg is
C5_C2/PENDING, notTRANSPORT/PENDING; there is noTRANSPORTleg anddispatchstays empty; outcomebecomescompliantonce the FTA report isREPORTED;GET /documents?reportOnly=truelists only documents addressed to one of the three predefined addresses (reportOnly=falseor omitted: no filter).
The buyer's TRN on these addresses follows the PINT-AE rule ibr-135-ae, not
a blanket requirement:
| Buyer address | Buyer TRN (IBT-048) |
|---|---|
0235:9900000099 with the export flag |
optional — a foreign buyer usually has no UAE TRN |
0235:9900000097, 0235:9900000098 |
a TRN or a buyer identifier (buyer.identifier, IBT-046) |
Without either, the document is refused with 422
BUYER_IDENTIFIER_REQUIRED at buyer.identifier before admission. The legal
registration identifier (IBT-047) does not replace them. buyer.identifier is
emitted as cac:PartyIdentification/cbc:ID without a scheme and is copied into
the FTA report. On every other address a tax invoice or tax credit note still
requires the buyer TRN (MANDATORY_FIELD); a commercial document does not.
In a CSV file (POST /ingest/file) the same value goes in the optional
buyer_identifier column; without it and without buyer_trn the invoice is
invalid with CSV_ROW at buyer_identifier. The PDF view prints it in the
buyer block as Buyer identifier.
For 0235:9900000098, the UAE Electronic Invoicing Guidelines (§10.2) also
require the supplier to give the buyer a conventional tax invoice (for
example a PDF). AXS does not deliver it for you: this is your obligation as
the issuer. You can download the document's PDF from /documents/{id}/pdf.
Tax category guidance
Version 1.6 · 2026-10-12 · category code list: PINT-AE 1.0.4 (ibr-139-ae) · review by our external tax adviser in progress — every row is provisional until it is complete.
This is guidance, not a decision. The right category follows from the facts of each transaction under UAE VAT law; AXS does not classify transactions for you, and no row replaces advice on your own case. When a row sends you to a tax adviser — or whenever you are unsure — ask before you issue the invoice.
The table maps common business situations to the tax category (IBT-151) and
the transaction-type flags (BTAE-02, transactionTypeCode) your ERP sends. AXS
never derives a category from a flag, a party or an amount: the category on
each line is the one you send. The same table, in English, Arabic and
Hungarian, is the portal help entry behind the tax-category selector. When a
row changes, its version and date change with it. A document whose lines are
all E or O is a commercial invoice (480) or a commercial credit note (81),
never a tax invoice: the rule set rejects E/O-only lines on a tax invoice
(ibr-151-ae) and any other category on a commercial document (ibr-122-ae).
Sources: [G] = UAE Electronic Invoicing Guidelines V1.1 (June 2026), section number; tax adviser = the written answers of our external tax adviser, which are not public; DL8.46 and AE-GoodsType = the published code lists of the installed rule set.
| Situation | Category · flag | On the document | Conditions | Ask a tax adviser when | Source |
|---|---|---|---|---|---|
| Domestic sale of goods or services to a business | S · no flag |
Each line at the standard rate (currently 5%) with its VAT amount. | The supply is taxable in the UAE and no zero rate or exemption applies to it. | the supply might be zero-rated or exempt — [G] 10.5 names exports and certain healthcare, education and real-estate supplies as zero-rated. | [G] 10.5; tax adviser |
| Export of goods to a customer outside the UAE | Z · Exports |
The 0% rate; the delivery address is mandatory; a foreign buyer without a Peppol ID gets the fixed export address 0235:9900000099. Add a reason code or wording only where the official code list prescribes one. For a qualifying zero-rated export use Z and keep the supporting export evidence (Guidelines §10.4). The PDF retains the category code; the cited sources prescribe no fixed export sentence. AXS does not create or verify that evidence for you. | Only a qualifying export is zero-rated ([G] 10.5); the conditions, including the evidence of export, come from the VAT law. | you are unsure whether the export qualifies for the zero rate or which evidence to keep. | [G] 10.4 (8); [G] 10.5; tax adviser |
| Services to a customer outside the UAE | Z / O · Exports |
Outside the scope (O) on a commercial invoice (480) when the place of supply is outside the UAE; the 0% rate (Z) on a tax invoice when the place of supply is in the UAE and the export conditions are met; otherwise the standard rate (S). On a tax invoice the Exports flag and its address rules apply as for goods. AXS does not accept the Exports flag on a commercial document ([G] 10.4 does not list the scenario for it), and the fixed export address requires that flag — whether an O-only export should carry the flag is an open question to our tax adviser. | Two steps. (1) Place of supply: VAT Decree-Law Article 29 places a service where the supplier resides, i.e. in the UAE; only the exceptions of Articles 30–31 move it abroad — a GCC-registered customer, services on goods or real estate abroad, catering, cultural, sporting or educational events abroad, transport starting abroad, and telecommunication or electronic services where they are used and enjoyed — and then the supply is O. (2) Place of supply in the UAE: Z only under VAT Executive Regulation Article 31 — the customer has no place of residence in an Implementing State and is outside the UAE when the service is performed (a presence in the UAE of less than 30 days that is not effectively connected with the supply counts as outside, Article 31(2); FTA VATP040 counts the days over a rolling 12-month period), the service is not connected to UAE real estate or movable property, the anti-avoidance test of ER 31(3) does not apply, or the service is actually performed outside the Implementing States (Article 31(1)(b)); otherwise S at 5% — and S whenever the facts for Z cannot be established (FTA VATP019). | always, before you choose between Z, O and S — in particular when the customer has a UAE presence or branch, the service relates to UAE real estate or movable property, ER 31(3) may apply, the customer is GCC-registered, or the customer has several establishments (FTA VATP019 names the most closely connected establishment). | [G] 10.4 (8); [G] 10.5; VAT DL Art. 29–31; VAT ER Art. 31; FTA VATP019; FTA VATP040 |
| Customer or supply in a free zone | no single category — see the conditions · Free zone | The beneficiary ID becomes mandatory: the party that ultimately uses, consumes or owns what is supplied — usually the buyer itself. | The flag records the free-zone fact; it does not decide the VAT treatment, and AXS does not derive a category from it or from the beneficiary. | the supply involves a designated zone — its VAT treatment depends on the facts and the designated-zone rules. | [G] 10.4 (1); tax adviser |
| Deemed supply: own use, gifts, supplies free of charge | no single category — see the conditions · Deemed supply | A tax invoice (380) is mandatory — VAT Decree-Law Article 65(2): deliver it to the recipient if there is one, otherwise keep it in your records. The buyer address is fixed to 0235:9900000097; the invoice is not exchanged, only reported to the FTA. Not available on commercial invoices or on self-billing. | A deemed supply is a taxable supply (Decree-Law Articles 2(1) and 3): the line carries S at the rate of the underlying supply; E is impossible (Article 12(2): an exempt supply is never deemed); Z only where the underlying supply itself is zero-rated — to be confirmed by our tax adviser. The value is the cost of the goods or services (Article 37) and the market value between related parties (Article 36). [G] 10.4 gives as examples supplies for no consideration, gifts above the prescribed threshold, private use of business assets, and goods held when the VAT registration is cancelled; the Decree-Law also lists exceptions. | always: whether the transaction is a deemed supply at all, how to value it, and whether its underlying supply is standard-rated or zero-rated. | [G] 10.4 (2); VAT DL Art. 2(1), 3, 12(2), 36, 37, 65(2) |
| Selling reverse-charge goods to a VAT registrant in the UAE | AE · no flag |
No VAT on the line; the GTIN and the type-of-goods code (BTAE-09) are mandatory, and the invoice must state why the reverse charge applies ([G] 10.5.1). The PDF states that the Recipient is required to account for VAT pursuant to Article 48 of Federal Decree-Law No. 8 of 2017 on Value Added Tax, as amended (VAT ER 59(1)(l)), with the paragraph the code carries: DL8.48.3.1–3 (oil, gas, hydrocarbons) cite Article 48(3); DL8.48.8.1–2 (gold and diamonds, electronic devices) cite Article 48(8) and add Cabinet Decision 91/2023 for electronics or 127/2024 for precious metals and stones; mixed or unknown codes keep Article 48 without a paragraph. The Arabic wording is our translation, pending review. | Both parties are VAT registrants, and the goods are among those [G] 10.5.1 lists: electronic devices, precious metals and precious stones, crude or refined oil, natural gas, pure hydrocarbons, metal scrap. Decree-Law Article 48(4) and Cabinet Decisions 91/2023, 127/2024 and 153/2025 require, before the date of supply, two written declarations from the buyer — the intended use (resale or processing) and its VAT registration — and the supplier to verify the buyer’s TRN and keep the declarations; the mechanism does not apply to a zero-rated supply. The code name “Gold and Diamonds” (DL8.48.8.1) is the vocabulary of the superseded Cabinet Decision 25/2018; silver, platinum and precious stones under Decision 127/2024 also use that code. Metal scrap (Decision 153/2025) has no code in the installed list, so an AE e-invoice for it cannot be issued. | the goods are metal scrap — the type-of-goods list of the installed rule set (AE-GoodsType) has no code for it — or you are unsure whether the goods, the buyer or the declarations fall under the reverse charge. | [G] 10.5; [G] 10.5.1; VAT DL Art. 48(4); VAT ER 59(1)(l); CD 91/2023, 127/2024, 153/2025; PINT-AE AE-GoodsType |
| Buying reverse-charge goods from a UAE supplier | AE · no flag |
The supplier issues the e-invoice with the AE category and no VAT; you receive it, and as the buyer you account for the VAT. | The same goods and the same registrant conditions as on the selling side. | you are unsure how to report the VAT you account for — that is your VAT return, outside AXS. | [G] 10.5.1; tax adviser |
| Importing goods or services from abroad (reverse charge) | no single category — see the conditions · no flag | No electronic invoice from you: the import of concerned goods and services is not subject to e-invoicing ([G] 10.5.1). | This is the import reverse charge, not the domestic one — the AE category is not used for it. | you are unsure how to account for the import VAT — that is your VAT return, outside AXS. | [G] 10.5; [G] 10.5.1 |
| Resale of second-hand goods, antiques or collectors’ items under the margin scheme | N · Margin scheme |
The structured invoice carries zero VAT as required by ibr-108-ae; this is not a VAT exemption. Under VAT ER 29(7), the PDF states “VAT charged on the profit margin” and omits the separate tax amounts — line VAT, the VAT breakdown and the VAT total, including its AED mirror on a foreign-currency document; the net, the gross total payable and its AED mirror stay (ER 59(1)(j)). The Arabic statement is our translation, pending review. | VAT ER 29(2) opens the scheme to second-hand goods, antiques over 50 years old and collectors’ items acquired without recoverable input tax; VAT is calculated only on the margin between purchase and resale price. [G] 10.4 gives a used car sold by a dealer and artwork bought from private collectors as examples. | you are unsure whether the goods, or the way you acquired them, qualify for the scheme. | [G] 10.4 (3); [G] 10.5; VAT ER 29(2); VAT ER 29(7); VAT ER 59(1)(j); FTA VATGPM1; ibr-108-ae |
| Financial services | E · no flag |
Category E with the exemption reason code DL8.46.1; no VAT. | Financial services exempt under Article 42 of the VAT Executive Regulation are excluded from e-invoicing ([G] 7.3), and so are such services to non-residents that qualify as zero-rated exports; financial services that are standard-rated to residents are not excluded. | always: first whether the service needs an e-invoice at all, then its category. | [G] 7.3; [G] 10.5; DL8.46 |
| Residential property (lease or sale) and bare land | E · no flag |
Category E with DL8.46.2 (residential) or DL8.46.3 (bare land); no VAT. A tax invoice needs at least one line outside E and O; a wholly exempt transaction goes on a commercial invoice (480). | [G] 10.5 names certain real-estate services as exempt and certain real-estate supplies as zero-rated — the same property can fall on either side. | always for real estate: whether the supply is exempt or zero-rated depends on the property and the supply. | [G] 10.5; DL8.46; tax adviser |
| Local passenger transport | E · no flag |
Category E with DL8.46.4; no VAT. | The exemption code names local passenger transport ([G] 10.5, DL8.46.4). | you are unsure whether the transport, or a service bundled with it, qualifies. | [G] 10.5; DL8.46 |
| Compensation, damages, deposits and similar payments | no single category — see the conditions · no flag | If the payment is outside the scope of VAT: category O. A document of O lines only is a commercial invoice (480), not a tax invoice. | FTA Public Clarification VATP001 (compensation-type payments) classifies them by the reason for the payment, whatever the parties call it: a payment that only compensates a loss — liquidated damages for a breach or an early termination, lost earnings, late payment interest on a contractual price, a true fine or penalty, compensation for goods damaged or lost — is not consideration for a supply and is outside the scope; a payment for something the recipient supplies, grants or gives up — the contractual price enforced in a dispute, a cancellation charge, a payment for the right to use property, taking title to the damaged goods, an administrative fee labelled as a penalty — is consideration and follows the supply it belongs to. An insurance payout is not among the VATP001 examples. [G] 10.5 describes out of scope only in general: the place of supply is outside the UAE, or the VAT Decree-Law excludes the transaction from being a supply. | always — whether a specific payment is compensation or consideration depends on the facts and the contract. | [G] 10.5; FTA VATP001; tax adviser |
| Advance payment received before the supply | no single category — see the conditions · no flag | A tax invoice for the advance when it is received, in the category of the supply. The final invoice covers only the remaining balance and references the advance invoice; the prepaid amount stays empty. | Where receiving the advance creates the date of supply for the amount received. | the contract has milestones or retentions — whether and when they create a date of supply depends on the contract. | [G] 17.1; tax adviser |
| Continuous or recurring supply: rent, subscription, instalments | no single category — see the conditions · Continuous supply | The Continuous supply flag; the category of the supply itself. No further field becomes mandatory. | FTA VATGRE1 §12.3: a completed/certified single supply under Article 25 is taxed on the full amount at completion (or earlier invoice/payment); on an Article 26 continuous supply, the retained part is taxed at the earliest of payment, its invoice or 12 months after certified completion. A milestone label alone is not a tax point. | retention is involved and the contractual classification is uncertain. Guidelines §17.2 permits the AED 90,000 + AED 10,000 pattern only as a conditional example; it does not automatically reduce the taxable amount. Clarify first: completed single supply or continuous/periodic supply; the contract’s payment and invoicing terms; when the retained part becomes due; whether an invoice already exists for it; whether a payment or another date-of-supply event has occurred (VAT Law Articles 25–26). See Continuous supply. | [G] 10.4 (5); [G] 17.2; FTA VATGRE1 §12.3; tax adviser |
| Summary invoice for several supplies over a period | no single category — see the conditions · Summary invoice | The invoicing period, and one line per supply with its description, taxable amount and tax treatment. A negative total is not allowed — use a credit note. A return goes on a credit note, not on a negative line; AXS warns on a negative line (SUMMARY_NETTED_RETURN). The Summary invoice flag is for tax invoices: the rule set rejects it on a commercial invoice (480) and on a commercial credit note (81) (ibr-157-ae, deliberate) — leave the flag off there and state the period in the invoicing period field (IBG-14). | Issue within 14 days from the end of the calendar month of supply (VAT Executive Regulation, Article 59(13)(b)). AXS uses the earliest stated supply-side month, or the period-end month if no earlier date is stated. The month-end day is excluded; if the last day is a weekend or an official Federal Government holiday, AXS moves it to the next Business Day (Tax Procedures Law, Articles 1 and 49). A continuous-supply flag alone does not activate the month-end rule. | you want to net a return inside the summary invoice — acceptable only where the current technical summary-invoice rules expressly permit it. | [G] 10.4 (4); VAT ER Art. 59(13)(b); TPL Art. 49; ibr-157-ae; tax adviser |
Summary invoice with a negative line. An accepted invoice can carry a
warnings list: advisory findings that never reject, store or send the
invoice differently. A summary invoice (transactionTypeCode position 4 is
1) with a line whose net amount (IBT-131) is negative gets one
SUMMARY_NETTED_RETURN warning per such line, in line order, with path
lines[i].netAmount. A return belongs on a credit note that references the
original invoice, not netted against unrelated supply lines. Credit notes do
not get this warning. A summary invoice whose total is negative is still
rejected with NON_NEGATIVE_AMOUNT; branch on the rule code, not on the
message.
Summary invoice spanning calendar months. A summary invoice whose stated
supply-side dates — invoicingPeriod.startDate, invoicingPeriod.endDate,
taxPointDate, delivery.actualDeliveryDate, paymentReceiptDate — fall in
more than one calendar month gets one SUMMARY_PERIOD_SPANS_MONTHS warning
with path invoicingPeriod.endDate; the message lists the months. The VAT
Executive Regulation allows one summary tax invoice only for the supplies of
one calendar month (Article 59(6), with the deadline in Article 59(13)(b)), so
supplies of another month belong on a separate summary invoice. The invoice
is still accepted and sent; the issuing-deadline basis is unchanged (it counts
from the end of the earliest stated supply month). Credit notes do not get this
warning; a malformed date is a field error instead. Line-level dates are not
modelled. It is the fourth and last producer in the fixed warnings order.
Secret rotation and revocation
A human tenant administrator, using the existing API-client screen, creates,
rotates and revokes clients. Its underlying tenant APIs (/api-clients,
/api-clients/:clientId/rotate, DELETE /api-clients/:clientId) require a human
tenant-admin principal; they are not an ERP client-credentials workflow.
A pending creation must be resumed, not recreated blindly. Secrets appear only
once on successful create/rotate/resume responses; list and revoke never reveal
one. A revoked client cannot be rotated back into service.
For planned rotation, agree a cutover with the administrator, receive the fresh
secret securely, replace the secret-manager value and obtain a new token using
the token command above. Rotation regenerates the Keycloak client secret; do
not assume a dual-secret overlap window. Verify a fresh /me and submission
with the new credential. On revoke, Keycloak disables the client before AXS
records REVOKED, preventing new token issuance by that client.
Already issued JWTs remain usable at the AXS API until their expiry, provided
the signature/issuer/audience/claims still verify. The API does not introspect
tokens or read the client's ACTIVE/REVOKED database state on each request.
Secret rotation or client disable does not itself invalidate those JWTs. The
exact remaining exposure follows their exp, not the time of the administrative
operation. In a credential incident, tell AXS about both the secret and any
issued tokens; do not assume revocation is immediate access-token cancellation.
API reference and boundaries
On your supplied tenant API base URL, open /reference for the existing
self-hosted Scalar reference, or /docs for Swagger. /docs-json serves the live
contract; the downloadable OpenAPI contract is versioned with
this guide. In Scalar, select the correct environment/server URL and enter your
bearer token and tenant header before trying a request. Generated local-server
examples are not a deployment URL. This portal never asks you to store a secret.
The contract covers more than the machine routes in this guide: some tenant routes
require a human session/role or another scope. Operator APIs (/ops/**) run
on a separate protected listener and are not part of the integrator handover.
Do not use an internal admin URL, operator credentials or a provisioning
service-account secret in ERP configuration.
Polling remains available. A human tenant administrator can configure the optional HTTPS callback described below when the deployment enables it. A self-service sandbox is not included. Documentation hosting/access and additional languages/themes are tracked in AXS-96; the full customer onboarding, external delivery receipts and usage-count rehearsal are tracked in AXS-144. This guide does not claim those deployment or onboarding checks have passed.
Tenant HTTPS callbacks
A human tenant-admin configures Manage → Callbacks, or the matching
GET /callbacks and PUT /callbacks tenant API. These are human administration
routes; ERP client-credentials tokens cannot change the destination or secret.
Read the current version and send it as expectedVersion when saving. A 409
means another administrator changed the configuration: reload before deciding.
available:false means the deployment is not ready to deliver callbacks.
Use a receiver you control, with valid HTTPS on port 443 and public IPv4 DNS. Credentials in the URL, query strings, fragments, IP literals, internal/local addresses and redirects are rejected. Every DNS answer must be public; the resolved address is pinned for each connection while TLS still verifies the original hostname. The request deadline is five seconds after DNS resolution.
Creation or explicit signing-secret rotation returns secret once. Store
it securely on the receiver; configuration reads never reveal it. Every save
creates a new version and cancels pending deliveries from the old version.
Prepare the receiver before enabling or rotating, and use pull access to recover
cancelled documents. Historical events are never sent to a newly chosen target.
AXS POSTs JSON with schemaVersion:1, id, tenantId, integrationId, type
and occurredAt. An inbound-document event also contains document, the
canonical invoice JSON. Receipt events use the established notification types:
outbound-delivered, outbound-failed, reporting-reported, reporting-failed,
fta-outage and inbound-rejected. The envelope and document are immutable for
that event ID.
inbound-rejected means AXS received a supplier's invoice for your company,
rejected it (the sender got a negative business response) and will not
deliver it as an inbound-document. It carries no document: fetch the details
with GET /documents/{integrationId} if you need them. Events that happened
before this type existed are not sent retroactively.
Forward compatibility. New type values can be added within
schemaVersion:1 without notice. A receiver must verify the signature, then
acknowledge an event with an unknown type with 2xx and ignore it. It must not
reject it or fail the batch. A change to the envelope's shape would come with a
new schemaVersion.
Validate the following headers before processing the body:
x-axs-event-id: must match the JSONid; durably deduplicate by tenant and ID.x-axs-timestamp: Unix seconds; reject timestamps outside your agreed freshness window (the controlled receiver uses five minutes).x-axs-signature:sha256=followed by the lowercase hex HMAC-SHA256 oftimestamp + "." + exact request-body bytes, using the one-time signing secret as a UTF-8 string. Compare signatures in constant time, then parse the JSON.
Return 2xx only after durably accepting the event; an already accepted duplicate
should also return 2xx without repeating the business action. Delivery is
at least once: a lost response can cause the same event to arrive again.
Only a received 2xx records DELIVERED; enqueue alone never does. Network errors,
408, 429 and 5xx retry with exponential backoff, at most six attempts per budget.
Other 3xx/4xx responses are permanent failures; AXS never follows a redirect.
GET /callbacks/deliveries and the portal show the latest 100 delivery results,
attempt counts and HTTP/error status. A human administrator can retry a DEAD
event with POST /callbacks/deliveries/:id/retry (URL-encode the ID). It preserves
the event ID/body and needs the same target configuration; pending, delivered
or cancelled events are not reopened by duplicate clicks. The receiver must
retain deduplication records across these operator retries. A 2xx proves HTTP
acceptance, not the receiver's subsequent accounting or ERP processing.
Credit-note adjustment fields
The optional internal adjustment.eventDate is a YYYY-MM-DD correction event date.
Its ground is the existing creditNoteReasonCode: DL8.61.1.A cancellation, B changed
nature/tax treatment, C changed consideration, D return and consideration repaid,
E tax/treatment applied in error (VAT Law 61(1)(a)–(e)). VD is separate, not a sixth ground.
For D both conditions must have occurred. The issuer/adviser determines the event.
The five events are a classification, not automatic credit-note grounds: a credit note is for a
reduction (VAT Law 62(2)); if the event results in more tax, send a new tax invoice (380)
referencing the earlier one; a treatment change without a monetary difference triggers neither
automatically. AXS does not check Article 61(2)–(3) and never derives the document kind.
For applicable tax corrections VAT Law 62(2) allows 14 days, excluding the event day;
an endpoint on a weekend or an official Federal Government holiday moves to the next
Business Day under TPL Articles 1 and 49 (holiday list: FAHR announcements, version 2026.1,
not yet complete for 2026 — see the issuing-deadline help).
Missing event: ISSUE_DEADLINE_NOT_ASSESSABLE; late: ISSUE_DEADLINE_EXCEEDED.
Both are advisory warnings, never a lateness-driven 422 or deletion. On commercial
credit notes and VD the calculation is a platform advisory, not an automatic legal duty.
No supply/payment/original-invoice/issue date substitutes for the event.
The event is stored and included with the reason in the atomic admission audit;
it never enters UBL/Peppol. CSV uses adjustment_event_date with credit_note_reason.
OpenAPI documents the same optional object and rejects a second adjustment.ground.
Supporting documents (attachments)
invoice.attachments carries the PINT AE additional supporting documents (IBG-24). Each
entry needs an id (IBT-122) and may carry a description (IBT-123), an embedded file and
an external location:
{"id":"TS-2026-07","description":"Timesheet July 2026",
"embedded":{"content":"<base64>","mimeCode":"application/pdf","filename":"timesheet-2026-07.pdf"}}
{"id":"DN-4471","externalUri":"https://erp.example.com/delivery-notes/4471"}
| Rule | Refusal (422, at the field) |
|---|---|
id not blank (ibr-052) |
ATTACHMENT_ID at attachments[i].id |
mimeCode is one of application/pdf, image/png, image/jpeg, text/csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/xml, application/vnd.oasis.opendocument.spreadsheet (ibr-cl-24, exact, lower case) |
ATTACHMENT_MIME |
mimeCode is not image/png or image/jpeg (AXS rule: no QR code or barcode on the electronic invoice, [G] 5.3) |
ATTACHMENT_IMAGE_REFUSED at attachments[i].embedded.mimeCode |
filename not blank (ibr-075) |
ATTACHMENT_FILENAME |
content is non-empty standard base64 |
ATTACHMENT_CONTENT |
| the decoded files of one invoice total at most 512 KiB | ATTACHMENT_SIZE at the file that crosses it |
| at most 10 supporting documents | ATTACHMENT_COUNT at attachments |
externalUri is an absolute https:// or http:// address, at most 2048 characters |
ATTACHMENT_URI |
description not blank when present |
ATTACHMENT_DESCRIPTION_BLANK |
The PINT AE pack allows PNG and JPEG, but an issued invoice may not carry them: the UAE
rules do not allow a QR code or barcode on the electronic invoice, an image could carry
one, and its content cannot be checked. Send a scanned document as application/pdf.
The accepted types at issue are therefore application/pdf, text/csv,
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/xml
and application/vnd.oasis.opendocument.spreadsheet. Documents you RECEIVE are not
affected: an image attachment from another provider is delivered to you unchanged.
The size and count limits and the URI shape are AXS rules (the PINT AE pack has none); the
512 KiB keeps the base64 body inside the 1 MiB request limit with room for the invoice.
Every embedded file is malware-scanned before admission. An infected file is refused with
422 ATTACHMENT_MALWARE at attachments[i].embedded.content, quarantined (its
fingerprint, never the bytes) and nothing is admitted. When the scan cannot run, the
answer is 503: retry the identical request later. A document without an embedded file is
never scanned. The file travels unchanged to the buyer on the Peppol network and inside the
FTA tax data document. CSV upload has no attachment column.