When an ERP issues an invoice that is correct in accounting terms and the Zakat, Tax and Customs Authority rejects it anyway, the problem is rarely "submission". It is more often an incomplete VAT number, an item code that does not satisfy the invoice rules, a document sequence broken during a migration, or a certificate bound to the wrong environment. So connecting an ERP to ZATCA starts by naming who owns the whole process: from the moment the invoice is created inside the system to the moment it is accepted, with an audit record you can go back to later.
A successful integration does not require replacing the ERP you already run. What it requires is an integration layer responsible for mapping the invoice data, validating it, signing it, submitting it along the right path for the transaction type, and then returning a trustworthy status to the operational system. The clearer and the more observable that path is, the lower the cost of rejections and manual intervention as document volumes rise.
What to settle before you start
Before you open an API or request a certificate, define which legal entities and which invoices are in scope. A group running several subsidiaries in the Kingdom does not treat this as one configuration: each entity has its own tax registration, its own invoice sequence and its own regulatory data, and may need separate operating permissions and data isolation — which is the subject of invoicing across several legal entities.
Then separate standard tax invoices from consumer invoices, and immediate clearance from subsequent reporting, according to ZATCA's requirements and the document type. That distinction changes submission timing, the customer's experience at the point of sale, and how you handle a temporary loss of connectivity. It is not a decision for the technology team alone: the tax team should own the policy definition, while the systems team owns its implementation and documentation.
Ask, too, where the source of truth is for every field. Does the buyer's VAT number come from the customer record or from the sales screen? Is VAT calculated in the ERP or in an external pricing engine? And does the system allow an already-submitted invoice to be edited? The answers decide where validation belongs and where errors are stopped before they become a regulatory rejection.
Connecting an ERP to ZATCA in practice
1. Inventory the document flow and the fields
Start by mapping the invoice's real path, not the one assumed in the project documents. Record where it is created, the issuing approvals, the postings, credit and debit notes, cancellations, and sales from branches or digital channels. Review the exceptional cases as well: the deferred invoice, an online sale when connectivity fails, or a document reissued after an operational error.
Then map ERP fields onto what is required by the regulator: seller and buyer details, the VAT number where it applies, referenced invoice numbers, goods or service lines, tax rates, discounts, totals and currency. Do not treat the mapping as a spreadsheet handed over once: make it a versioned technical contract, because any change to a source field can land directly on compliance. Understanding the e-invoice's XML structure as the Authority requires it helps here.
2. Build a mapping layer independent of the ERP model
ERP data models differ between products and sectors, while the Authority's requirements are fixed. That is why mapping is better isolated in an integration layer than planted inside invoicing screens or database procedures. The layer receives invoice data in one canonical shape, applies the mapping rules, and produces the regulatory document required.
The practical decision here is whether to build that layer in-house or rely on a specialist provider. Building in-house gives the team fine-grained control, but it also transfers the burden of tracking schema updates, certificates, signing, monitoring and failure handling. A specialist platform reduces that burden — provided its responsibilities are explicit, its audit logs are available, and it supports legal-entity isolation without holding your data or your keys hostage.
3. Validate before signing and submitting
ZATCA should not be the first party to discover an error in your invoice data. Add a validation layer ahead of signing that covers mandatory fields, consistency of totals, correct VAT rates, document sequencing, and the reference rules for corrected invoices. That layer should return actionable errors — "the buyer's VAT number is required for this transaction" — rather than a generic technical message. We have collected the most common rejection codes and what they mean as a starting point for your own rules.
The policy on blocking issuance varies by operation. In a fast-moving store you may need to pass the invoice into a processing queue, show a pending state and watch it afterwards. In high-value corporate invoicing, refusing to approve the invoice until validation passes may be the lower-risk option. No single policy suits everyone, but the policy must be stated and enforced in code.
4. Onboard the unit and manage certificates safely
Onboarding and certificate issuance is not a marginal administrative step. It is the identity of your invoicing unit before the Authority, and it has to be carried out per environment and per legal entity under the approved controls. Keep a clear record of what was registered, who approved the step, when certificates expire, and the renewal plan — before expiry reaches production. The full path is in registering the electronic seal certificate.
And do not keep private keys in ERP settings, shared files or code repositories. Use managed key storage, and hardware modules for signing where the architecture calls for it, with duties separated between whoever administers certificates and whoever ships production changes. This is not security theatre: losing control of a signing key creates a compliance risk and an operational one at the same time.
5. Signing, the QR code, and submission along the invoice's path
Once validation passes, the invoice data is produced in the required format, signed and stamped to ZATCA's requirements, the QR code is generated, and the document is submitted along the appropriate path. Storing the invoice file after generating it is not enough: the submission result has to be tied to the internal invoice number, the external request identifier, and a status the finance team can read.
For invoices that require clearance, do not treat the document as final before the Authority accepts it. Where reporting applies, the deadline and the receipt status both need watching. Design the integration to be safely retryable without duplicating invoices: a unique identifier per document, and a status record that cannot be misread, reduce double submission when integration services restart or the network drops.
6. Return the status to the ERP without confusing users
A one-way integration leaves the finance team chasing invoice statuses in a second portal. Return intelligible states to the ERP: under validation, awaiting submission, accepted, rejected, or action required. Attach the rejection reason in directed form, and name who handles it — the customer-data team, tax, store operations, or integration. What rejection means for your record deserves a separate read before you design these states.
Webhooks can carry the status back, but do not rely on them alone. Run periodic reconciliation queries too, because a notification may be delayed or fail even though the invoice was processed successfully. The standard is not that one message arrived; it is that the invoice's status matches across the ERP, the integration provider's record and the Authority's state.
7. Test the normal cases and the exceptional ones
One successful test invoice proves nothing about readiness. Test multi-line invoices, line-level and document-level discounts, different tax rates, credit notes, returns, currencies, repeated requests, and the absence of buyer details where they are not required. Test the end-of-day rollover, loss of connectivity, certificate failure and delayed responses as well.
Running a parallel phase that compares the new system's output against current output before full launch is worth the effort, as long as test data never mixes with production. Write down the exit criteria: an expected success rate, a processing time, a rejection-handling method, and an escalation path when the service stops. Those criteria turn the project from "an integration that was switched on" into a service you can depend on.
Four control points to settle before development
Integration success is not measured by the first invoice accepted in the sandbox; it is measured by the organisation's ability to run thousands of documents and prove what happened to each one. Before any code is written, agree on four things:
- Data ownership. Who owns the invoice number, the issue time, the customer's VAT number, and the line and discount detail? Every field needs one authoritative source, because a contradiction between the ERP and the invoicing platform shows up later in reconciliation.
- Rejection policy. Does a rejected document return to draft automatically? Does an alert reach the tax team? Who is allowed to correct customer or tax data and resubmit? Logging a technical error code without a named owner is not a policy.
- Certificate and key management. The private key is not a file to pass between developers or store in application settings. Signing keys belong in dedicated security hardware, with restricted permissions and a log of access, rotation and replacement.
- Reconciliation and monitoring. Finance needs a report matching invoices issued from the ERP against documents accepted or reported, while technology needs monitoring of queues, rejection rates, response times and retries.
Do not make the regulator's format a contract on every internal system
A common mistake is wiring every system directly to the regulatory document format. The result is duplicated logic across the ERP, the points of sale and the web storefronts, and real difficulty when you expand to another legal entity or another country. The more sustainable model is one canonical inbound data shape, mapped inside the compliance layer onto local requirements.
In practice that means a single JSON shape, with no application team handling UBL detail in every flow. The commercial fields stay intelligible to the business team, while the integration layer takes care of structure, tax rules and the required references before signing and submission.
Monitoring and audit after launch
The integration does not end at the first accepted invoice. Watch the volume of accepted and rejected documents, recurring rejection reasons, processing time, queue age, certificate validity, and any gap between invoices issued and invoices that reached the Authority. When something breaks, teams need an audit record that answers precisely: who submitted what, when, under which version of the mapping rules, and what response came back. Invoice storage and the audit trail carry their own statutory requirements.
For high-volume organisations, the architecture has to support asynchronous processing, controlled retries, and isolation so one legal entity's failure does not reach another. Any executing operation through AI assistants or operations tooling should also run under scoped permissions with mandatory human approval in production. Automation is useful for diagnosing errors and searching logs; it does not mean granting the right to change or resubmit documents without controls.
How this looks in alFatora - الفاتورة
alFatora Connect is the operational compliance layer between your systems and the Authority: your system sends one JSON shape, and we carry the mapping, pre-submission validation, signing and stamping, QR generation, clearance or reporting by document type, and the status back to you.
What matters specifically to an integration team:
- A unique key per request. Submission requires an idempotency key, and retrying with the same key never creates a second document; the same key with a different payload is refused with an explicit conflict rather than passing silently.
- Failed validation consumes nothing. A document that falls at pre-submission validation takes no number and no counter value, and its idempotency key stays valid for a retry after correction.
- Scoped access keys. Separate permissions for writing documents, managing webhooks, and reading company data, balance and audit — so an integration key never sees more than its job needs.
- A status for every document over webhooks. Including an awaiting-clearance state when the Authority's service slows or stops, so the invoice sits in a governed queue rather than in a void.
- An immutable audit trail tying the original request, the validation result, signing, submission, the Authority's response, and any retry.
The commercial model follows the same logic: credits burn on documents the Authority actually accepts in production, and the sandbox is free and unlimited — so rejections, failed validation and integration experiments never land on the customer's bill.
A good integration is not measured by how fast the first invoice goes out, but by your ability to know where every document stands and to take the right action when things do not go to plan. Start by defining ownership, data and exceptions, then make compliance a visible, measurable part of the invoicing cycle rather than a hidden task that surfaces only at a rejection or an audit.
Frequently asked questions
Do I have to replace my ERP to meet ZATCA requirements?
No. The ERP stays the source of commercial data, and an integration layer carries mapping, validation, signing and submission to the Authority, then returns each document’s status to the ERP.
How do I stop an invoice being submitted twice when the network drops?
Give every document a unique idempotency key sent with the request, so a retry with the same key returns the first request’s result instead of creating a second document.
What should come back to the ERP after submission?
A clear status per document — under validation, awaiting submission, accepted, rejected, or action required — with the rejection reason and the Authority’s request identifier.
Was this useful? Review alFatora on Google.