API reference
E-invoices
Invoices your own system issued, cleared with the FTA through KWN in one call.
Send an invoice for clearance
POST/einvoices
Send an Idempotency-Key header.
In one step: checks the seller TRN, finds or creates the buyer (by TRN, then by exact name), creates the KWN invoice under KWN's number, approves it and claims it — the claim takes exactly one credit and queues it for Taxstar. 201 with the e-invoice, PENDING. The same externalId with the same content answers the first invoice (200, duplicate: true) and takes no second credit; a rejected invoice sent again corrected is resubmitted (200, resubmitted: true). Any refusal leaves nothing behind. Requires Idempotency-Key and the scopes sales:approve.
Parameters
| Field | Type | Description |
|---|---|---|
Idempotency-KeyHeaderRequired | string | 1 to 100 visible ASCII characters, such as a UUID, unique to this request. Sent again with the same request, the first answer is replayed (Idempotent-Replayed: true); with another request, 422 IDEMPOTENCY_KEY_REUSED. |
Request body
31 fields
| Field | Type | Description |
|---|---|---|
externalId | string | Your system's id for the invoice; 1–100 visible ASCII characters. |
sellerTrn | string | Must be this company's TRN. |
issueDate | date | The invoice day, YYYY-MM-DD. |
lines | object[] | |
lines[].description | string | |
lines[].quantity | number | |
lines[].unitPrice | number | VAT-exclusive unit price. |
lines[].taxRate | number | VAT percent: 5 or 0. |
lines[].productId | string | |
lines[].productCode | string | A product's SKU, then its barcode. |
lines[].uom | string | |
lines[].discount | number | |
externalNumber | string | The number your system shows; kept as a reference. |
dueDate | date | |
customerId | string | An existing contact by id … |
customer | object | |
customer.name | string | |
customer.isCompany | boolean | |
customer.trn | string | 15 digits for a UAE company: matched first. |
customer.email | string | |
customer.phone | string | |
customer.address | string | |
customer.city | string | |
customer.emirate | ABU_DHABI | DUBAI | SHARJAH | AJMAN | UMM_AL_QUWAIN | RAS_AL_KHAIMAH | FUJAIRAH | |
customer.country | string | ISO 3166 alpha-2; AE by default. |
customerRef | string | |
notes | string | |
paymentTermId | string | |
paymentMeansCode | string | |
transactionFlags | FREE_TRADE_ZONE | DEEMED_SUPPLY | MARGIN_SCHEME | SUMMARY_INVOICE | CONTINUOUS_SUPPLY | DISCLOSED_AGENT_BILLING | ECOMMERCE | EXPORTS[] | |
expectedTotal | number | When set, the invoice must add up to it to the fils, or it is refused EINVOICE_TOTAL_MISMATCH. |
Code samples
curl -sS -X POST "https://app.kwn.tax/api/v1/einvoices" \
-H "X-Api-Key: $KWN_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"externalId": "INV-2026-00042",
"externalNumber": "INV/2026/00042",
"sellerTrn": "100234567800003",
"issueDate": "2026-10-15",
"dueDate": "2026-11-14",
"customer": {
"name": "Al Noor Trading L.L.C.",
"isCompany": true,
"trn": "100398765400003",
"email": "accounts@alnoor.example",
"address": "Office 1204, Bay Square, Business Bay",
"city": "Dubai",
"emirate": "DUBAI",
"country": "AE"
},
"paymentMeansCode": "30",
"lines": [
{
"description": "Bookkeeping, October 2026",
"quantity": 1,
"unitPrice": 2500,
"taxRate": 5
},
{
"description": "VAT return preparation",
"quantity": 1,
"unitPrice": 750,
"taxRate": 5
}
],
"expectedTotal": 3412.5
}'Responses
200OK
Field Type Description idstringexternalIdstringexternalNumberstringnumberstringKWN's number: the number cleared with Taxstar. statusstringPENDING, CLEARED, REJECTED, FAILED or CANCELLED. documentStatusDRAFT | SENT | CONFIRMED | ISSUED | SUBMITTED | PROCESSING | APPROVED | REJECTED | FAILED | PAID | CANCELLED | EXPIREDissueDatedatecustomerobjectsubtotalnumbertaxTotalnumbertotalnumberclearanceobjectduplicatebooleanTrue when this answers an invoice already received with the same content. resubmittedbooleanTrue when a rejected invoice was corrected and sent again. createdAtdateupdatedAtdate201Created
Field Type Description idstringexternalIdstringexternalNumberstringnumberstringKWN's number: the number cleared with Taxstar. statusstringPENDING, CLEARED, REJECTED, FAILED or CANCELLED. documentStatusDRAFT | SENT | CONFIRMED | ISSUED | SUBMITTED | PROCESSING | APPROVED | REJECTED | FAILED | PAID | CANCELLED | EXPIREDissueDatedatecustomerobjectsubtotalnumbertaxTotalnumbertotalnumberclearanceobjectduplicatebooleanTrue when this answers an invoice already received with the same content. resubmittedbooleanTrue when a rejected invoice was corrected and sent again. createdAtdateupdatedAtdate400Refused: the request or a business rule. The code says which (REQUEST_INVALID, RULE_REFUSED, …).
{ "error": "Lines: at least one line is required.", "code": "REQUEST_INVALID" }401No key, a key that is not ours, or one revoked (API_KEY_INVALID); a merchant not active (MERCHANT_INACTIVE).
{ "error": "That API key is not valid, or it was revoked.", "code": "API_KEY_INVALID" }403The key's scopes do not carry the capability (APP_NOT_GRANTED, ROLE_TOO_LOW), or the plan lacks the app (APP_LOCKED).
{ "error": "This key's scopes do not include sales.approve.", "code": "ROLE_TOO_LOW" }404Not found: another type under this route, or another company's (NOT_FOUND).
{ "error": "Not found.", "code": "NOT_FOUND" }409A conflict: an externalId taken, or a change that could not be saved (EXTERNAL_ID_TAKEN, CONFLICT).
{ "error": "That externalId is already used by another record of this company.", "code": "EXTERNAL_ID_TAKEN" }422That Idempotency-Key was used for a different request (IDEMPOTENCY_KEY_REUSED).
{ "error": "That Idempotency-Key was used for a different request.", "code": "IDEMPOTENCY_KEY_REUSED" }429Too many requests: wait retryAfter seconds (RATE_LIMITED).
{ "error": "Too many requests. Wait a little and try again.", "code": "RATE_LIMITED" }
List e-invoices
GET/einvoices
The invoices that came in through this endpoint, newest first. Poll with updatedSince for status changes; filter by externalId, status (PENDING, CLEARED, REJECTED, FAILED, CANCELLED) and issueFrom/issueTo.
Parameters
| Field | Type | Description |
|---|---|---|
statusQuery | string | A status, by name. |
partnerIdQuery | string | The customer (sales) or the vendor (purchases). |
issueFromQuery | date | Issued on or after this day. |
issueToQuery | date | Issued on or before this day. |
numberQuery | string | |
limitQuery | integer | 1 to 200; 50 by default. |
cursorQuery | string | The previous page's next. |
updatedSinceQuery | date | Only rows changed at or after this instant. |
createdFromQuery | date | |
createdToQuery | date | |
externalIdQuery | string | Only the row your system gave this id. |
Code samples
curl -sS -X GET "https://app.kwn.tax/api/v1/einvoices" \
-H "X-Api-Key: $KWN_API_KEY"Responses
200OK
Field Type Description dataobject[]The rows of this page. nextstringThe cursor of the next page, to send as ?cursor=; null on the last page. 400Refused: the request or a business rule. The code says which (REQUEST_INVALID, RULE_REFUSED, …).
{ "error": "Lines: at least one line is required.", "code": "REQUEST_INVALID" }401No key, a key that is not ours, or one revoked (API_KEY_INVALID); a merchant not active (MERCHANT_INACTIVE).
{ "error": "That API key is not valid, or it was revoked.", "code": "API_KEY_INVALID" }403The key's scopes do not carry the capability (APP_NOT_GRANTED, ROLE_TOO_LOW), or the plan lacks the app (APP_LOCKED).
{ "error": "This key's scopes do not include sales.approve.", "code": "ROLE_TOO_LOW" }404Not found: another type under this route, or another company's (NOT_FOUND).
{ "error": "Not found.", "code": "NOT_FOUND" }409A conflict: an externalId taken, or a change that could not be saved (EXTERNAL_ID_TAKEN, CONFLICT).
{ "error": "That externalId is already used by another record of this company.", "code": "EXTERNAL_ID_TAKEN" }429Too many requests: wait retryAfter seconds (RATE_LIMITED).
{ "error": "Too many requests. Wait a little and try again.", "code": "RATE_LIMITED" }
Read an e-invoice
GET/einvoices/{id}
Where the invoice stands: PENDING while with the provider, CLEARED with its reference, REJECTED or FAILED with the provider's errors.
Parameters
| Field | Type | Description |
|---|---|---|
idPathRequired | string |
Code samples
curl -sS -X GET "https://app.kwn.tax/api/v1/einvoices/<id>" \
-H "X-Api-Key: $KWN_API_KEY"Responses
200OK
Field Type Description idstringexternalIdstringexternalNumberstringnumberstringKWN's number: the number cleared with Taxstar. statusstringPENDING, CLEARED, REJECTED, FAILED or CANCELLED. documentStatusDRAFT | SENT | CONFIRMED | ISSUED | SUBMITTED | PROCESSING | APPROVED | REJECTED | FAILED | PAID | CANCELLED | EXPIREDissueDatedatecustomerobjectsubtotalnumbertaxTotalnumbertotalnumberclearanceobjectduplicatebooleanTrue when this answers an invoice already received with the same content. resubmittedbooleanTrue when a rejected invoice was corrected and sent again. createdAtdateupdatedAtdate400Refused: the request or a business rule. The code says which (REQUEST_INVALID, RULE_REFUSED, …).
{ "error": "Lines: at least one line is required.", "code": "REQUEST_INVALID" }401No key, a key that is not ours, or one revoked (API_KEY_INVALID); a merchant not active (MERCHANT_INACTIVE).
{ "error": "That API key is not valid, or it was revoked.", "code": "API_KEY_INVALID" }403The key's scopes do not carry the capability (APP_NOT_GRANTED, ROLE_TOO_LOW), or the plan lacks the app (APP_LOCKED).
{ "error": "This key's scopes do not include sales.approve.", "code": "ROLE_TOO_LOW" }404Not found: another type under this route, or another company's (NOT_FOUND).
{ "error": "Not found.", "code": "NOT_FOUND" }409A conflict: an externalId taken, or a change that could not be saved (EXTERNAL_ID_TAKEN, CONFLICT).
{ "error": "That externalId is already used by another record of this company.", "code": "EXTERNAL_ID_TAKEN" }429Too many requests: wait retryAfter seconds (RATE_LIMITED).
{ "error": "Too many requests. Wait a little and try again.", "code": "RATE_LIMITED" }