Your XML validates, your signature verifies, and the Authority still will not accept an invoice. None of it counts until the establishment is onboarded to the Fatoora platform and your solution holds a certificate the Authority issued. This is that handshake, in order, with the honest cause behind each way it fails — the companion to what a direct integration really involves, which is about the code you write. New to clearance and reporting? Start with what Phase 2 requires.
The OTP is an onboarding code, not a login code
The most misunderstood object here is six digits long. The one-time password is generated by the taxpayer from the Fatoora portal, and it authorises one issuing unit to obtain a certificate and sign for that establishment: the Authority's evidence that whoever asked was authorised by someone who can sign in to that account.
- Not a password. It grants no portal access and identifies no user.
- Used once. A failed attempt still consumes it: treat a code that errored as spent.
- Short-lived, minutes rather than days, so the certificate request must exist before the code is generated.
- Bound to one environment. The portal has an environment selector, and a code issued for one environment does not work in another. This is the single most common reason onboarding fails.
That last failure looks nothing like its cause: the code is fresh, correct and refused. The environment is chosen when the code is generated, encoded again in the certificate request your software builds, and fixed by the endpoint you call. Pin all three together first.
The sequence, and what each step produces
Four steps, then a fifth that comes round again.
| Step | What it produces | What it proves | What fails there |
|---|---|---|---|
| OTP from the portal | Six digits, single use, short-lived | The establishment authorised this unit | Expired, consumed, wrong environment |
| Key pair and CSR | A private key you keep, and a request carrying the establishment's details and document types | Nothing yet; it is a request | Details disagree with the Authority's record |
| Compliance CSID | A certificate that can run the checks and nothing else | The Authority accepts this key for this establishment | Spent code, or wrong environment |
| Compliance checks | A pass on samples of every type the unit issues | Your generator makes documents the Authority validates | A type your code cannot build |
| Production CSID | The certificate that signs live invoices, with an expiry date | This unit may issue for real | Signing later with the compliance pair |
| Renewal | A fresh production certificate | The same, to the same standard | Nothing visible; it simply lapses |
How many compliance documents, really
It depends on which document types the unit is registered to issue, which the certificate request declares. A solution registered for both standard and simplified invoices is checked on both, and on the credit and debit note of each: the familiar six. One registered for a single type is checked on that type alone. Any figure quoted without that qualification is a guess.
The samples must come from the code path that will produce your real invoices, signed and chained exactly as production documents are: the exercise tests the generator, not the sample. And a sample accepted with warnings passes — only a hard error stops the run — so a defect carrying a warning severity travels through onboarding into production, where it is returned on every response and rejects nothing.
Where onboarding actually fails
- An expired or already-used code. Ordinary, and easy to mistake for something structural.
- A code from the wrong environment. Nothing in the response points at it, so check it first.
- Establishment data that does not match the Authority's record. Usually the address: the national address has six elements, street name, building number, postal code, city, district and country, and the last two are the ones nobody has to hand. At invoice validation the shortfall appears as BR-KSA-09, severity warning — the invoice is accepted and the complaint returned beside it, which is why it survives for months.
- A malformed VAT number. Fifteen digits, the first and last being 3; a commercial registration number in the wrong field, a stray space or Arabic-Indic digits all fail it. This one is an error: BR-KSA-40 rejects the invoice. Check a number with the VAT number lookup.
One device, or several
The issuing unit holds its own certificate, its own invoice counter and its own hash chain. A cloud system issuing through a single queue needs one; three points of sale that can each ring up a sale in the same second need three: two issuers building on the same previous hash claim the same position in the chain.
Design for that rather than discover it: the Authority will not stop you. Both chain rules, BR-KSA-61 (the previous invoice hash must be present) and BR-KSA-26 (it must be a Base64-encoded SHA-256 digest, computed as the specification sets out), carry a severity of warning. Documents from a diverging chain are accepted and handed to customers, the complaint returned quietly beside each acceptance. Nothing bounces, so nobody looks, and what is lost is the tamper-evidence the chain existed to provide: it surfaces in an audit, not at submission. The counter is stricter, BR-KSA-33 being an error.
Renewal, and the silence
The production certificate has a validity period, and renewal runs the same path: fresh key pair, fresh certificate request, fresh OTP, once per unit. It is the onboarding you just finished, on a day nobody scheduled.
The dangerous property is that expiry is silent. No grace period, no banner: submissions simply stop being accepted. Standard invoices can no longer be cleared, so the document you owe a business buyer cannot be issued at all, while simplified ones keep printing at the till as every report fails behind them, leaving a backlog whose 24-hour windows run out unattended. Record the expiry date the day you connect, against a named owner. Forty branches means forty renewals.
Verify instead of assuming
Do not trust the checklist that says you are connected. Issue one real invoice and read its QR code: a Phase 2 QR carries eight TLV fields where a Phase 1 QR carried five, and three of the extra ones, the invoice hash, the signature and the public key, cannot exist unless the document was genuinely stamped. Read a five-field code and nothing is being signed, whatever the dashboard says. Our free QR code reader decodes them field by field, beside the other free tools.
Then check what a configuration file hides: that the credentials in use are the production pair, not the compliance pair they resemble, and that the environment is the live one — a test environment accepts everything and reports nothing to anybody. Rejections afterwards carry a code, listed in the error code reference and explained in how to read a rejection.
Or hand the handshake over
ZATCA Tools does this handshake for you: one OTP, and we generate the certificate request, obtain the compliance certificate, run the compliance checks and obtain the production certificate. Then signed invoices with a compliant QR, cleared or reported; signed XML archived six years and downloadable; rejections shown with the official code and a link to its guide, from 135 documented codes, 24 with full guides; and a device, certificate and chain per branch. Integrations for WooCommerce, Shopify, n8n and WHMCS, a REST API, and a Partner API for software companies serving many merchants (see the partner guide). Not an accounting system. Free during the launch period, starting at 50 invoices and expanding: create an account, talk to us, or read on at the English blog.