Skip to content

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.

Every one returns an object, not an array

The response is a map keyed by the enum member name:

{ "IN_CASH": { "code": 10, "description": "In cash", "description_ar": "نقداً" },
  "CHEQUE":  { "code": 20, "description": "Cheque",  "description_ar": "شيك" } }
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/ UN/ECE Rec 20 units
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:

{ "vat_rates": [5.0, 15.0], "reasons": [], "is_free_text": false }

Standard rated allows 5.0 and 15.0. Zero, exempt and not-subject are 0.0 and require a reason. 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

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.

Units of measure

PCE piece · CTN carton · PALLET · BOX · TNE tonne · MTK square metre · LTR litre, and others from UN/ECE Recommendation 20.

Arabic labels

Most entries carry description_ar. Two gaps to expect rather than treat as errors:

  • Some allowance codes have description_ar: null.
  • Charge codes (UNTDID 7161) have no Arabic at all.

Fall back to the English description when the Arabic is absent.

Other lookups

These are not on the integration surface but are public — no key required:

Path What
GET /api/buyers/additional-buyer-id-types/ TIN, CRN, MOM, MLS, 700, SAG, NAT, GCC, IQA, PAS, OTH
GET /api/sellers/additional-seller-id-types/ CRN, MOM, MLS, SAG, OTH
GET /api/business-types/ 1000 B2B, 0100 B2C, 1100 Both
GET /api/industries/ Industry list
GET /api/plans/ Plans and their features

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.