In any business issuing invoices at high volume, the hardest question is not «how do I sign a single invoice» but «where does the compliance layer sit in my architecture, and who is responsible for signing, sending, and retrying when the network fails». This guide answers that. We cover the integration architecture patterns for ZATCA Phase 2 e-invoicing in Saudi Arabia: where to place the signing and compliance layer, when to connect directly and when to use a middleware, and how to build a queue-based asynchronous issuance flow that withstands failures and scales as the business grows.
This documentation is aimed at developers, architects, and technical accountants designing an invoice issuance system, or connecting an existing system to a compliance-ready invoicing layer aligned with the Zakat, Tax and Customs Authority (ZATCA). We focus here on high-level architectural decisions, not endpoint details. The API details themselves (authentication, formats, endpoints) are covered in the series API Integration with the Fatoora Platform within E-Invoicing by Qoyod.
Before we begin, an important clarification: Qoyod is not an ERP and does not claim to replace a resource-planning system in a factory or a complex supply chain. Qoyod is an integrated accounting system that provides a Phase 2-compliant e-invoicing layer. When you build your own architecture, Qoyod can be the ready-made compliance layer that receives the invoice data, generates the UBL document, signs it, and connects it to the Fatoora platform. This is the third option we will discuss shortly.
What «integration architecture» specifically means here
Many developers confuse «integration» in the sense of connecting two systems with «architecture» in the sense of distributing responsibilities across system components. In the context of e-invoicing, by integration architecture we mean the following:
- Where the compliance layer sits: Do you build XML generation and signing inside your system, isolate it in a standalone service, or consume it from a ready-made provider.
- How the invoice flows: Is it issued instantly with the sales request (synchronous), or does it pass through a queue and get processed later (asynchronous).
- How the system handles failure: What happens when the Fatoora platform rejects an invoice, the network drops, or the system exceeds rate limits.
- How the system scales: Does the design handle ten invoices per minute, or ten thousand, without one operation clashing with another.
The governing idea in everything that follows is separation of concerns (separation of concerns): the business system stays responsible for sales logic, and the compliance layer stays responsible for composing, signing, and sending the document. Mixing the two responsibilities in a single codebase is the number-one cause of fragile invoicing systems that are hard to maintain.
Where the signing and compliance layer sits
Every architectural decision in e-invoicing starts from this question: where does the cryptographic signing and compliant-document generation take place. This layer carries three responsibilities that a business system does not usually perform.
- Generating an XML document compliant with the UBL 2.1 standard from the raw invoice data.
- Cryptographically signing the document using the CSID certificate tied to the invoice-generation unit.
- Managing the chaining between consecutive invoices via the ICV counter and the previous invoice hash (PIH).
This layer is security-sensitive because it holds the private signing key. Therefore the first design rule: Isolate the signing layer within clear boundaries, do not scatter signing logic inside every service that issues an invoice. The service that holds the private key should be the fewest possible components, and the most heavily audited.
For a deeper look at the signing unit and certificate, see The Electronic Generation System (EGS) Unit, which explains the unit’s structure, its relationship to the CSID certificate, and how a device or branch is bound to it.
An EGS unit per device: an architectural decision, not a minor detail
The Authority treats the invoice-generation unit at the device or point-of-issuance level, not at the level of the business as a whole. Each EGS unit has its own CSID certificate, an independent ICV chain, and its own PIH sequence. This forces an early architectural decision: how you model devices and branches inside your design.
In a retail store with ten cashiers, you have ten potential EGS units and ten separate ICV chains that must not overlap. If two cashiers issued two invoices with the same counter value, the Authority would reject them. Your design must therefore ensure that each EGS unit has its own atomic counter, not a counter shared across devices. This is one of the most common architectural mistakes in high-volume systems.
Three architectural patterns: direct, middleware, and compliant provider
Every team faces three main patterns for placing the compliance layer. There is no absolute «best» pattern, only one that fits your volume, your team, and your capacity to maintain it. We present them in order from the most control to the most ready-made.
Pattern one: Direct Integration
In this pattern your team builds everything inside your system: UBL generation, signing, and connecting to the Fatoora platform directly via its API. Your system talks to the Clearance API and theReporting API with no intermediate layer.
When it fits: When your team has deep cryptography expertise, you want full control, and you have the capacity to continuously track updates to the technical specification.
The real cost: You bear the burden of staying compliant with every update to the UBL standard and validation rules, managing the CSID certificate lifecycle and its renewal, and handling every signing detail. This is a permanent maintenance burden that does not end at launch.
| Criterion | Direct integration | Via a compliant provider |
|---|---|---|
| Signing layer | You build and maintain it yourself | Ready-made with the provider |
| Maintenance burden | High | Low |
| Best suited for | Large technical teams | Most businesses |
Pattern two: Middleware
Here you isolate the compliance layer in a standalone middleware service. Your various systems send raw invoice data to this service, and it takes care of UBL generation, signing, and sending. The middleware is a single layer serving multiple source systems.
When it fits: When you have more than one invoice source (a sales system, a point of sale, an online store) and you want a single compliance logic you do not duplicate. The middleware unifies signing and validation rules in one place, making maintenance simpler.
The architectural advantage: This pattern applies separation of concerns in its cleanest form. Each source system cares only about its business logic, and a single layer cares about compliance. When the Authority’s specification changes, you modify one place.
Pattern three: using a compliant provider (such as Qoyod)
In this pattern you do not build the compliance layer at all. You consume a ready-made provider accredited by the Zakat, Tax and Customs Authority. You send the invoice data, and the provider generates the document, signs it, connects it to the Fatoora platform, and returns the signed result to you.
When it fits: When you want to focus on your product rather than compliance details, and you prefer that a specialized party bear the burden of tracking specification updates, renewing certificates, and managing the ICV and PIH chains.
The trade-off: You gain speed in implementation and reduce the maintenance burden, in exchange for a dependency on the provider’s API. This option is the best fit for most small and medium businesses whose core work is not cryptographic compliance.
Make Qoyod the ready-made compliance layer in your architecture
Instead of building signing and managing certificates yourself, connect your system to an invoicing layer accredited by the Zakat, Tax and Customs Authority, and focus on your product.
Queue-based asynchronous issuance
The second architectural question, after «where does the compliance layer sit», is «when is the invoice issued». Here the decisive difference between synchronous and asynchronous design emerges.
In a synchronous design, the user presses «confirm sale», and the system waits until the Fatoora platform responds before completing the operation. This looks simple, but it ties the user experience to the response time of an external service. If the Fatoora platform slows down or the network fails, your sales stop. This design does not hold up at high volume.
In a queue-based asynchronous design, the system separates «recording the invoice» from «sending it for compliance». The business system writes the invoice to a queue and responds to the user immediately. Then a worker service pulls invoices from the queue at a rate it controls, processes each invoice independently, and records the result.
This design achieves three gains at once. First, it separates the user experience from the Authority’s response time. Second, it enables controlling the send rate to respect the Rate Limits of the API. Third, it makes retrying simple: the failed invoice stays in the queue until it succeeds or is diverted to an error path.
Remember the important regulatory difference here: standard B2B invoices need instant clearance before being handed to the customer, while simplified (B2C) invoices are issued instantly to the consumer and reported to the Authority within 24 hours. The queue-based design serves both cases, but processing priority differs: clearance invoices are processed at the front of the queue, and simplified ones can tolerate a longer delay within the 24-hour window.
Business system
Queue
Throttled worker
Fatoora platform
Retry logic and the dead-letter queue
Any system that talks to an external service must assume failure, not hope for success. The Fatoora platform may respond with a transient error (network outage, rate-limit exceeded) or a permanent error (an invoice rejected for violating validation rules). A sound design distinguishes between the two.
Transient errors deserve a retry. But do not retry immediately in a tight loop, because that compounds the pressure and consumes the rate limit. Use exponential backoff: wait one second, then two, then four, and so on, with an upper limit on the number of attempts. The details of this pattern are in Retry Logic.
Permanent errors do not deserve a retry. An invoice rejected because it violates Validation Rules will be rejected a thousand more times. These must be diverted immediately to a human-review path with the rejection reason, not left spinning in the queue.
Here is where the dead-letter queue (dead-letter queue) comes in. Every invoice that has exhausted its attempts or been rejected for a permanent reason is diverted to this separate queue. This achieves two goals: it prevents failed invoices from blocking the main queue, and it provides a single place your team monitors for invoices that need intervention. A system with no dead-letter queue is a system that silently swallows its errors.
An important architectural rule: process each invoice in full independence. If you send a batch of fifty invoices and one is rejected, the remaining forty-nine must continue. Do not let one invoice’s failure bring down an entire batch. Independence is what lets the system recover partially instead of collapsing entirely.
Separation of concerns: who owns what
Everything above rests on a single principle: each component has one clear responsibility. When responsibilities mix, every change becomes risky. Here is the correct distribution of responsibilities in a mature invoicing architecture.
- The business system The source of truth for sales data: products, prices, customers, tax categories. It knows nothing about cryptographic signing.
- The compliance layer The source of truth for the compliant document: UBL generation, signing, ICV and PIH management. It knows nothing about pricing logic or discounts.
- The queue Responsible for temporal decoupling and resilience: it holds invoices between creation and sending, and enables retrying.
- The monitoring layer Responsible for visibility: it logs every invoice and its status, and alerts when the dead-letter queue fills up.
When the master data is owned once in the business system, and consumed only by the compliance layer, you prevent data forking. If each system kept its own copy of the tax categories, conflicting invoices would appear. Always keep a single source of truth.
High availability and runtime environments
E-invoicing is not a peripheral feature; it is a prerequisite for completing the sale in many cases. The compliance layer must therefore be designed to high-availability standards, not as a secondary service.
Three practical principles achieve this. First, worker redundancy: run more than one processing worker, so if one goes down the others keep pulling the queue. Second, a durable queue: make the queue write to durable disk, so if the service restarts the unprocessed invoices are not lost. Third, environment isolation: never test on production.
This last principle deserves emphasis. Build and test your integration first in a Sandbox environment, where you try out signing, sending, and retrying with no real effect. When you are confident, move to the Production Environment with a separate production CSID certificate. Mixing the two environments causes test invoices in the production record, and that is a mistake that is hard to clean up.
Multiple workers on a durable queue
Separating the sandbox from production
An independent CSID certificate per environment
Dead-letter queue + monitoring dashboard
Linking the device pattern here matters too. When you distribute issuance across several branches, each branch is served by its own EGS unit. A high-availability design ensures that one branch going down does not disrupt the rest, and that each ICV chain stays connected and independent. This pattern is explained from the branch perspective in Invoice Integration with POS Systems, and from the large-systems perspective in Invoice Integration with ERP Systems.
How to choose the right pattern for your business
The first and most important architectural decision is choosing the pattern: direct, middleware, or compliant provider. There is no single correct answer, but four questions reveal the best fit for your case.
Question one: how much cryptographic expertise does your team have? Cryptographic signing, certificate management, and hash chains are a specialized field. If your team lacks deep expertise in it, building the signing layer from scratch is a risk. In this case, a compliant provider is a safer choice.
Question two: how many invoice sources do you have? If you have only one system issuing invoices, direct integration is reasonable. But if the sources are multiple (sales, point of sale, online store, mobile app), a middleware saves you from duplicating compliance logic in every system.
Question three: what is your expected volume in two years? Design for your future volume, not your current one. A system issuing a hundred invoices a day today may issue ten thousand in two years. The queue-based pattern and the compliant provider both scale without re-engineering, whereas simple direct integration may need a rebuild.
Question four: is compliance the core of your business? If you are building an invoicing product you sell to others, full control via direct integration may be your competitive advantage. But if invoicing is merely a compliance requirement on the margin of your core product, there is no point in bearing the burden of building and maintaining it yourself.
The practical rule: most small and medium businesses find that a compliant provider is the smartest choice, because it converts a permanent engineering burden into a ready-made service. Large businesses with specialized teams may prefer the middleware to combine control with unified logic. Full direct integration remains the least common, suited only to special cases.
Idempotency and oversight
There is a hidden risk in every queue-and-retry system: issuing the same invoice twice. Imagine a worker sent an invoice, and it was cleared successfully on the Fatoora platform, but the success response was lost to a network outage before it reached your system. The system will think the invoice failed, so it resends it, and two invoices appear for a single sale. This is a serious compliance error.
The solution is to design the operation to be idempotent (idempotent): sending the same request more than once yields the same result with no double effect. In practice, give each invoice a stable unique UUID from the moment it is created in the business system, not at send time. When you retry, send the same identifier. This lets the compliance layer recognize that this invoice was already processed, and return the stored result instead of generating a new document.
The unique UUID is not just a minor technical detail; it is an architectural tool that prevents duplication. For more on its structure, see The Unique Identifier (UUID) in the E-Invoice.
The final pillar in any mature architecture is observability. At every moment you must know: how many invoices are in the main queue, how many in the dead-letter queue, what the success rate is, and the average processing time. Log every invoice and its status (pending, processing, cleared, rejected, diverted), and connect a dashboard that alerts your team when the dead-letter queue fills up or the rejection rate suddenly rises. A system that issues invoices without visibility into their status is a system that discovers its failures from customer complaints, not from your dashboards.
Bring these principles together and you get a robust architecture: clear separation of concerns, queue-based asynchronous issuance, retry with exponential backoff, a dead-letter queue, idempotent operations, high availability, and comprehensive observability. This is not engineering luxury; it is what separates an invoicing system that holds up at high volume from one that collapses at the first network outage.
How Qoyod helps you
If you read all of the above and felt that building and maintaining the compliance layer is a burden you do not want to carry, that is exactly what Qoyod solves. Qoyod provides a ready-made e-invoicing layer accredited by the Zakat, Tax and Customs Authority, which receives your invoice data and takes care, on your behalf, of generating the UBL document, signing it with the CSID certificate, connecting it to the Fatoora platform, and managing the ICV and PIH chains.
In practice, this architecture means you do not write signing code, do not track technical-specification updates, and do not renew certificates manually. You focus on your product and your sales, and Qoyod handles the compliance layer in all its complexity. And when your volume grows, the system absorbs the increase without you re-engineering the invoicing layer again.
Try Qoyod free for 14 days, no credit card required.
Frequently asked questions
Is Qoyod an ERP that replaces my current system?
No. Qoyod is an integrated accounting system that provides a Phase 2-compliant e-invoicing layer. When you have an existing system, Qoyod works as a compliance layer that receives the invoice data, generates the UBL document, signs it, and connects it to the Fatoora platform.
Which architectural pattern should I choose: direct, middleware, or provider?
Direct integration suits teams with deep cryptographic expertise and a desire for full control. A middleware suits those with multiple source systems who want a single compliance logic. Using a compliant provider such as Qoyod suits most small and medium businesses that want fast implementation and a lighter maintenance burden.
Why do I need queue-based asynchronous issuance?
Because it separates the user experience from the Fatoora platform’s response time, enables controlling the send rate to respect rate limits, and simplifies retrying. Synchronous design stops your sales when the external service slows down or fails.
What is the difference between a transient error and a permanent error?
A transient error (network outage, rate-limit exceeded) deserves a retry with exponential backoff. A permanent error (an invoice violating validation rules) does not deserve a retry; it is diverted immediately to human review with the rejection reason.
What is the role of the dead-letter queue?
It is a separate queue to which invoices that have exhausted their attempts or been rejected for a permanent reason are diverted. It prevents failed invoices from blocking the main queue, and provides a single place your team monitors for manual intervention.
Why does each EGS unit need an independent ICV counter?
Because the Authority treats issuance at the device level, and each EGS unit has its own CSID certificate, ICV chain, and PIH sequence. If two devices shared one counter, they would issue two invoices with the same value and the Authority would reject them, so each counter must be atomic and independent.