ZATCA results
Every sales invoice and credit note carries a zatca object that says where it stands with ZATCA. If ZATCA is new to you, read Start here first.
{
"kind": "standard",
"status": "cleared",
"uuid": "e7f8a9b0-c1d2-4e3f-a4b5-c6d7e8f9a0b1",
"counter": 18,
"hash": "zXab+32ksuccBzrDiE27f65AmOvbZ2ixbnSSRnoRKzA=",
"qr": "ARBTYW5kYm94IE1lcmNoYW50Ag8zOTk5OTk5OTk5MDAwMDMDFDIwMjYtMTEtMDdUMDk6NDE6MjJaBAYyMzAuMDAFBTMwLjAw",
"submittedAt": "2026-11-07T09:41:21.884Z",
"clearedAt": "2026-11-07T09:41:22.517Z",
"reportedAt": null,
"errors": []
}
| Field | Meaning |
|---|---|
kind | standard for a company customer, simplified for a person |
status | pending, cleared, reported or rejected |
uuid | the document's UUID in ZATCA's records |
counter | ZATCA's invoice counter value |
hash | the document's hash, which the next document chains to |
qr | the QR code in Base64; on a standard document, the one ZATCA returned when it cleared it |
submittedAt | when Kosoor signed the document, in UTC |
clearedAt | when ZATCA cleared a standard document, in UTC |
reportedAt | when ZATCA accepted the report of a simplified document, in UTC |
errors | ZATCA's messages when it rejected the document, each with code, category and message |
uuid, counter, hash, qr and submittedAt are null until Kosoor signs the document.
What to do with each status
pending
The document is issued and valid in Kosoor; ZATCA has not accepted it yet.
- Simplified: this is the normal state right after issue. Kosoor reports the document after its reply, and it turns
reported. Its PDF is ready at once; its XML answers409 invoice_not_cleareduntil ZATCA accepts the report. - Standard: ZATCA did not answer while Kosoor was clearing it. Kosoor sends it again later, and it turns
clearedorrejected. Until then its PDF and XML answer409 invoice_not_cleared, and a credit note against it answers409 invoice_not_clearedtoo.
Do not issue the sale again: a new invoice is a second sale. If your request timed out and you do not know whether it went through, send it again with the same Idempotency-Key, which returns the first reply.
cleared
ZATCA cleared this standard document. Its PDF and XML are ready, and qr holds ZATCA's QR code. Nothing to do.
reported
ZATCA accepted the report of this simplified document. Its XML is ready. Nothing to do.
rejected
ZATCA refused the document. errors holds its messages:
{
"kind": "standard",
"status": "rejected",
"uuid": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"counter": 20,
"hash": "PO9Je+Enxi/tc010iSgP6H+piJDaQh6zQZ41v6aDPsk=",
"qr": "ARBTYW5kYm94IE1lcmNoYW50Ag8zOTk5OTk5OTk5MDAwMDMDFDIwMjYtMTEtMDdUMTA6MDI6MTFaBAYxMTUuMDAFBTE1LjAw",
"submittedAt": "2026-11-07T10:02:11.430Z",
"clearedAt": null,
"reportedAt": null,
"errors": [
{ "code": "BR-KSA-63", "category": "KSA", "message": "Buyer street is missing" }
]
}
The document stays in Kosoor, but:
- its XML answers
409 invoice_not_clearedfor good, and so does a standard document's PDF; - an invoice ZATCA rejected cannot be credited through the API (
422 invoice_not_creditable).
Show the merchant ZATCA's messages. The merchant corrects the sale on the Kosoor dashboard.
When ZATCA rejects a standard invoice at issue
A standard invoice is cleared before Kosoor replies. If ZATCA rejects it then, nothing is saved, no number is used, and the call answers 422 zatca_rejected with ZATCA's messages in zatcaErrors:
{
"error": {
"type": "business_rule_error",
"code": "zatca_rejected",
"message": "ZATCA rejected the invoice, so nothing was saved. ZATCA's messages are in zatcaErrors.",
"param": null,
"docUrl": "https://docs.kosoor.com.sa/errors#zatca_rejected",
"zatcaErrors": [
{ "code": "BR-KSA-63", "category": "KSA", "message": "Sandbox sample rejection: the buyer's street is missing" }
]
}
}
Fix the data ZATCA names, usually on the customer with PATCH /v1/customers/{id}, and send the invoice again under a new Idempotency-Key. The same holds for a credit note on a standard invoice.
In the sandbox, the fixture customers Sandbox ZATCA Pending Co and Sandbox ZATCA Rejected Co give these two outcomes every time. See Test mode.
Results that arrive later
A document that answered pending gets its result later, and Kosoor pushes it to your system: register a webhook endpoint for the salesInvoice.zatca* and creditNote.zatca* events. See Webhooks. Without one, read the document again with GET /v1/sales-invoices/{id} or GET /v1/credit-notes/{id} when your system needs its status, and use zatcaStatus=pending on either list to find the documents still waiting.