Reference data¶
The codes ZATCA expects on an invoice. All are static enumerations served from memory, available to any authenticated key, and safe to cache for a long time.
Three more lookups give the ids a client or a note needs: see Business types, industries and reasons.
Every one returns an object, not an array
The response is a map, not a list. Seven of the eight are keyed by the enum member name:
{ "IN_CASH": { "code": 10, "description": "In cash", "description_ar": "نقداً" },
"CHEQUE": { "code": 20, "description": "Cheque", "description_ar": "شيك" } }
/api/invoices/vat/ is keyed by the category code instead (S, Z, E, O). Use Object.values() if you want a list. Code that assumes an array will break on every one of these.
The endpoints¶
| Path | What it gives you |
|---|---|
GET /api/invoices/vat-categories/ |
S, Z, E, O |
GET /api/invoices/vat/ |
Valid rates and reasons per category |
GET /api/invoices/vat-exemption-reasons/ |
The 16 VATEX-SA-… codes |
GET /api/invoices/invoice-type-codes/ |
388, 381, 383, 386 |
GET /api/invoices/units-of-measure/ |
41 units of measure |
GET /api/invoices/payment-means-types/ |
UN/CEFACT 4461 payment means |
GET /api/invoices/invoice-charges-codes/ |
UNTDID 7161 charge reasons |
GET /api/invoices/invoice-allowances-codes/ |
UNTDID 5189 allowance reasons |
VAT categories¶
| Code | Meaning |
|---|---|
S |
Standard rated |
Z |
Zero rated |
E |
Exempt from VAT |
O |
Not subject to VAT |
GET /api/invoices/vat/ tells you what each category permits. Without a parameter it returns all four; ?vat_category_code=S returns one:
Standard rated allows 5.0 and 15.0. Zero, exempt and not-subject allow only 0.0, and reasons lists their exemption codes as {"code", "text", "text_ar"}. On an invoice line in any category other than S, vat_exemption_reason_code and vat_exemption_reason_text are required. Only O sets is_free_text: true, meaning you supply your own wording instead of picking a code.
An unknown category returns 400 {"message": "Invalid VAT Category"}.
Exemption reasons¶
Sixteen codes, filterable with ?category=Z:
VATEX-SA-32, -33, -34-1 … -34-5, -35, -36, -EDU, -HEA, -MLTRY, -29, -29-7, -30, -OOS
Each entry is {"category", "code", "description_en", "description_ar"}: note description_en, not description as on the other lists. An unknown category returns an empty object, not an error.
Use the one that matches the actual ground for exemption — it is a tax declaration, not a label.
Invoice type codes¶
| Code | Document |
|---|---|
388 |
Tax invoice |
381 |
Credit note |
383 |
Debit note |
386 |
Advance payment invoice |
Payment means¶
10 in cash · 20 cheque · 23 bank cheque · 25 certified cheque · 26 local cheque · 30 credit transfer · 31 debit transfer · 46 interbank debit transfer · 48 bank card · 49 direct debit · 54 credit card · 55 debit card
code is a number here
For payment means and invoice types the code field is an integer (10, 388), not a string. Compare accordingly. On the invoice payload, type_code is an integer too, but payment_means_type_code is a string: send "10", not 10.
Units of measure¶
41 units, among them PCE piece · KGM kilogram · LTR litre · MTK square metre · TNE tonne · CTN carton · BOX · PALLET. The list is Clix's own; it does not carry every UN/ECE Recommendation 20 code.
Two codes appear under two names each: LTR (LITRE, LITRE_PER_LITRE) and STN (TON_UK, SHORT_TON). Key your cache on code and you get one entry for each.
Arabic labels¶
Every list carries Arabic except one:
- Charge codes (UNTDID 7161) have no Arabic field at all.
- Allowance codes (UNTDID 5189) all carry
description_artoday, but the schema allowsnull.
Fall back to the English description when the Arabic is absent.
Business types, industries and reasons¶
Creating a client needs a business type and an industry. A credit or debit note may name a reason. Each list has its own endpoint. Unlike the eight above, each returns an object that holds an array.
| Field | Where the value comes from |
|---|---|
business_type on client_data |
uuid from GET /api/business-types/ |
industry on client_data |
id from GET /api/industries/ |
reason_id on a credit or debit note |
uuid from GET /api/sellers/reasons/ |
additional_buyer_id[].type_id on client_data |
No endpoint. One of TIN, CRN, MOM, MLS, 700, SAG, NAT, GCC, IQA, PAS, OTH. |
Business types¶
GET /api/business-types/. Any valid key; no role needed.
{ "business_types": [
{ "uuid": "…", "type": "B2B", "type_ar": "شركة إلى شركة", "code": "1000" },
{ "uuid": "…", "type": "B2C", "type_ar": "شركة إلى مستهلك", "code": "0100" },
{ "uuid": "…", "type": "Both", "type_ar": "كلاهما", "code": "1100" } ] }
Send the uuid, not the code. An empty list also carries "message": "No business types found.".
Industries¶
GET /api/industries/. Any valid key; no role needed. Only active industries are listed.
{ "industries": [
{ "id": "…", "name": "…", "name_ar": "…", "description": "…", "is_active": true } ] }
The UUID is in id here, not uuid.
Reasons¶
GET /api/sellers/reasons/. Any key; ViewInvoice is enough. Lists your own organisation's reasons, 10 to a page.
{ "reasons": [
{ "uuid": "…", "name": "…", "name_ar": "…",
"description": "…", "description_ar": "…",
"reason_type": { "code": 381, "value": "CREDIT_NOTE" },
"is_active": true, "created_at": "…", "updated_at": "…", "created_by": "…" } ],
"total": 1, "num_pages": 1, "current_page": 1 }
Inactive reasons are listed too. A note accepts only an active one, so filter: ?is_active=true&reason_type=381 for credit notes, 383 for debit notes. Other parameters: page, page_size, search_text, name, start_date, end_date, and sort (A-Z, the default, Z-A, latest, oldest).
What does not exist¶
There are no endpoints for countries, cities, regions or currencies. city is free text on an address — validate it your side if you need to.
Caching¶
These change only when ZATCA changes a standard. Fetch at start-up, cache for a day, and you will never notice them.
Related¶
- Codes and constants — every value in a payload or response, with meaning and accepted alternatives
- Quickstart
- Invoice types
- API reference