Test mode
Build against a sandbox before you touch the merchant's real data. A test key works exactly like a live one, on the same host and paths, but every call reaches the merchant's sandbox: a separate copy of their catalogue whose invoices are signed with ZATCA's test certificates and never reach their real ZATCA records.
Getting a test key
The merchant creates the sandbox in the dashboard under Settings → Developers → Sandbox, then issues a test key under Settings → Developers → API keys. A test key starts with ksr_test_:
Authorization: Bearer ksr_test_7c1e...
Every reply to a test key carries the header Kosoor-Mode: test. Check it in your client if you want to be sure a call did not reach live data.
What the sandbox holds
- The merchant's branches, items, payment methods, chart of accounts and warehouses, copied when the sandbox is built.
- None of their customers, invoices or payments. Create your own, or use the fixtures below.
- The merchant's name and address, with ZATCA's test VAT number
399999999900003.
PDFs from the sandbox carry a red Test, not a tax invoice mark. The sandbox sends no SMS.
When the sandbox is busy
While the sandbox is being built or reset, a test key answers 503 sandbox_unavailable with a Retry-After: 30 header. Wait and send the same request again.
If the sandbox could not be built, a test key answers 503 sandbox_failed with no Retry-After: retrying will not help until the merchant resets the sandbox. While the sandbox is being deleted, its test keys answer 401 invalid_api_key.
A reset rebuilds the sandbox from the merchant's current catalogue. Your test keys keep working; every document and the request log are cleared. Deleting the sandbox stops every test key.
Fixtures
Every sandbox holds these customers and one item under fixed ids, each with a known outcome. Use them to exercise your error handling without arranging the data yourself.
| Id | Name | Outcome |
|---|---|---|
5a4db0c5-0000-4000-8000-000000000001 | Sandbox Person | a simplified invoice succeeds |
5a4db0c5-0000-4000-8000-000000000002 | Sandbox Standard Co | a standard invoice is cleared |
5a4db0c5-0000-4000-8000-000000000003 | Sandbox CRN Co | a company with a commercial registration and no VAT number; a standard invoice is cleared |
5a4db0c5-0000-4000-8000-000000000004 | Sandbox No Street Co | a standard invoice is refused: 422 customer_address_incomplete |
5a4db0c5-0000-4000-8000-000000000005 | Sandbox Gulf Trading | a company in the UAE; a standard invoice is cleared |
5a4db0c5-0000-4000-8000-000000000006 | Sandbox Inactive Person | any invoice is refused: 422 customer_inactive |
5a4db0c5-0000-4000-8000-000000000007 | Sandbox Credit Limit Co | credit limit 100; an invoice on account above it answers 422 credit_limit_exceeded |
5a4db0c5-0000-4000-8000-000000000008 | Sandbox ZATCA Pending Co | a standard invoice answers 201 with zatca.status pending, and is cleared shortly after |
5a4db0c5-0000-4000-8000-000000000009 | Sandbox ZATCA Rejected Co | a standard invoice is refused: 422 zatca_rejected, with a sample BR-KSA-63 in zatcaErrors |
5a4db0c5-0000-4000-8000-000000000101 | Test subscription (item) | a line naming it is refused: 422 item_not_sellable |
Fixtures 8 and 9 never reach ZATCA when the invoice is issued: their answers come from Kosoor, so they are the same every time.