In large enterprises, an invoice is not issued from a standalone screen. It is created inside the Enterprise Resource Planning (ERP) system the moment a sales order is confirmed or a shipment is posted, and from there it must be turned into an electronic document compliant with Phase Two in Saudi Arabia. That exact point, namely how the data inside an ERP system reaches the Fatoora platform in a valid, signed format, is the subject of this guide.
This documentation is aimed at developers and technical accountants who connect an existing ERP system (SAP, Oracle, Microsoft Dynamics, or an in-house system) to an electronic invoicing layer compliant with the Zakat, Tax and Customs Authority (ZATCA). We focus on the integration pattern between the ERP and the invoice: how ERP fields are mapped to UBL document elements, how issuance is managed at high volume, and how master data is synchronized. This guide is part of the series technical documentation for electronic invoicing.
Before we begin, an important clarification: Qoyod is not an ERP system, and it does not claim to replace an ERP system in a factory or a complex supply chain. Qoyod is an integrated accounting system that provides an electronic invoicing layer compliant with Phase Two. When an enterprise already owns its own ERP system, integration comes into play: the ERP system holds the business logic, and the invoicing layer takes care of generating the UBL document, signing it, and sending it to the Fatoora platform.
The difference between ERP integration and other invoicing integrations
The technical documentation series covers three different connection scenarios. Confusing them causes design errors, so we clarify the dividing line between them first.
- ERP integration (this guide): The invoice originates in a large resource-planning system. Volume is high, data arrives in batches, and the biggest challenge is mapping fields and synchronizing master data between two independent systems.
- Point-of-sale (POS) integration: The invoice originates from a cashier device in a retail store. Invoices are simplified (B2C), issued instantly to the consumer, and reported to the Authority within 24 hours. The context is entirely different from ERP.
- API integration: This is the technical specification of the programming interface itself: the endpoints, the authentication, and the request and response formats. Any system, whether ERP or POS, ultimately consumes this interface.
In other words: API integration describes the pipe, and ERP integration describes how the resource-planning system pumps its data into that pipe. This guide assumes you understand the API layer and builds a high-volume ERP scenario on top of it.
How an ERP system connects to the compliant invoicing layer
The core integration pattern is simple in principle: the ERP system generates the invoice data in its internal format, then this data is converted into a signed UBL 2.1 document, then it is sent to the Fatoora platform for clearance in the case of standard B2B invoices, or for reporting in the case of simplified invoices.
The invoicing layer is the intermediary that performs three tasks the ERP system does not normally perform: generating XML compliant with the UBL standard, cryptographic signing using a CSID certificate, and managing the hash chain between successive invoices. The ERP system remains the source of truth for business data, and the invoicing layer remains the source of truth for compliance.
ERP generates the invoice
Conversion layer to UBL 2.1
Signing (CSID, UUID, hash, and QR)
Fatoora platform: clearance or reporting
Where does the integration layer live?
There are two common patterns for the location of the invoicing layer relative to the ERP system:
- The embedded pattern: The invoicing layer exists as a module or an add-on inside the ERP system itself. All data stays within a single environment, and the connection to the Fatoora platform goes out directly from the ERP system.
- The middleware pattern: The invoicing layer exists as an independent service between the ERP system and the Fatoora platform. The ERP system sends the invoice data over an API to this service, and it takes care of conversion, signing, and sending. This pattern is more common when connecting a legacy ERP system that does not support the Phase Two requirements at all.
In the middleware pattern, an accounting system such as Qoyod plays the role of this intermediary service: it receives the invoice data from the ERP system over the API, generates a compliant UBL document, and handles the connection to the Fatoora platform on behalf of the ERP system. The details of connecting to the Authority are explained in the guide on connecting to the Zakat, Tax and Customs Authority.
Mapping ERP fields to UBL document elements (Field Mapping)
The most important and most error-prone stage in ERP integration is field mapping. Every ERP system names and arranges its fields in its own way. The electronic invoice document, by contrast, follows a fixed UBL 2.1 structure that leaves no room for improvisation. The integration layer’s job is to translate from the first to the second accurately.
To review the full structure of the invoice document and its three sections, see the guide on the electronic invoice structure, and the guide on XML invoice: the technical format of the electronic invoice for the details of the XML format.
The following table shows examples of mapping typical fields from an ERP system to their corresponding UBL elements. The names on the left of the table are approximate and differ between systems, but the idea is constant.
| Field in the ERP system (example) | Corresponding UBL element | Note |
|---|---|---|
| DocumentNumber | cbc:ID | Invoice number, must be unique and sequential |
| PostingDate | cbc:IssueDate | In YYYY-MM-DD format |
| CompanyVATNo | cac:AccountingSupplierParty / CompanyID | Seller’s tax number |
| CustomerVATNo | cac:AccountingCustomerParty / CompanyID | Mandatory in B2B invoices |
| LineItemCode | cac:InvoiceLine / cac:Item / cbc:Name | Line item description |
| LineNetAmount | cac:InvoiceLine / cbc:LineExtensionAmount | Net line item value before tax |
| VATRate | cac:TaxCategory / cbc:Percent | 15 for the standard rate, 0 for exempt/zero-rated |
| DocumentTotal | cac:LegalMonetaryTotal / cbc:PayableAmount | Total due after tax |
The most common error at this stage is not forgetting a field, but placing the value in the wrong position within the UBL tree. The same number means something different if it is placed in the header, inside a line item, or in the totals section. Therefore, the field mapping must be validated against the official XSD schema before running the integration on real data.
Handling differences in data units
Mapping is not limited to moving a value from one slot to another. Some fields need a conversion in format or unit:
- Dates: Many ERP systems store the date in a local or numeric format. UBL requires the ISO 8601 format (YYYY-MM-DD) in the date field, and the separate time format in the time field.
- Currency: The compliant invoice uses the ISO currency code, that is SAR for the Saudi riyal, and not free text.
- Invoice type: An ERP system may distinguish between an invoice and a credit note by an internal field. UBL requires a document type code (InvoiceTypeCode) with a specific value for each type.
- Tax: The tax category (standard, zero-rated, exempt) must be translated into the correct UBL category code, not just a percentage.
Connect your existing system to compliant invoicing without writing XML
Qoyod generates the UBL document, signs it, and sends it to the Fatoora platform automatically, so your data stays in your system and Qoyod handles the compliance layer on your behalf.
High-Volume (Batch) Issuance
An enterprise issuing thousands of invoices a day cannot handle them one by one interactively. This is where the real challenge in ERP integration appears: how to issue large batches without the process breaking or exceeding the platform’s limits.
The fundamental rule to understand: standard B2B invoices need immediate clearance from the Fatoora platform before they are delivered to the buyer, while simplified B2C invoices are reported within 24 hours. This difference determines how batches are grouped.
| Criterion | Standard B2B invoice | Simplified B2C invoice |
|---|---|---|
| Timing | Instant clearance per invoice | Reporting within 24 hours |
| Delivery | After approval | Immediate, then reported |
| Pattern | One after another | Batches |
Queue processing pattern (Queue Pattern)
The recommended design for high-volume issuance is based on an asynchronous queue:
- The ERP system writes the ready invoices to a queue instead of sending them directly.
- The integration layer pulls the invoices from the queue at a steady rate that respects the Fatoora platform’s limits.
- For each invoice, a UBL tree is generated, signed, and sent.
- The result of each invoice (success, or rejection with a reason) is recorded in a log that the ERP system reconciles against.
The following example shows a simplified structure of a batch issuance request over the API:
And the expected response returns the status of each invoice individually, even if some succeed and some fail:
Handling partial rejection
In large batches, the rejection of a single invoice must not stop the whole batch. A sound design processes each invoice independently, then returns to the ERP a list of the rejected ones with their reason (a missing field, an invalid tax number, an error in the totals). The ERP system corrects the reason and resends the rejected invoice alone, not the entire batch.
Interruption cases must also be handled: if the connection to the Fatoora platform drops in the middle of a batch, the same invoice must not be sent twice. Therefore, each request carries a unique identifier from the ERP system (erp_ref in the example above), and the integration layer verifies that the same reference has not been issued previously before retrying.
Master Data Sync
The invoice does not contain all of its data by itself. Many of its fields refer to master data stored in the ERP system: customer records, their tax numbers, the product catalog, and tax categories. If this data differs between the ERP system and the invoicing layer, inconsistent or rejected invoices arise.
Therefore, ERP integration needs a clear strategy for synchronizing master data, one that answers a pivotal question: which system is the source of truth for each type of data?
Customers and their tax numbers
Product and item catalog
Tax categories and their rates
Synchronization scheduled or real-time (Webhook)
The three synchronization patterns
- Scheduled synchronization: The invoicing layer pulls the master data from the ERP system at regular intervals (every night, for example). Simple, but it may leave a window in which the data is stale.
- Event-driven synchronization: The ERP system sends a notification (webhook) when a new customer or product is created or modified, so the invoicing layer is updated immediately. More accurate, but it requires an event infrastructure in the ERP system.
- Just-in-time synchronization: Data is not synchronized in advance. When issuing an invoice for a customer that does not exist in the invoicing layer, their data is fetched from the ERP system at that moment. It reduces duplicate storage, but it adds latency to every new invoice.
The practical rule: make the ERP system the single source of truth for master data, and make the invoicing layer only a consumer of it. Do not allow a customer’s tax number to be edited from the invoicing layer directly, otherwise the two copies diverge and invoices start carrying conflicting data.
Authentication and connection security between the ERP and the invoicing layer
The connection between the ERP system and the invoicing layer carries sensitive financial data and cryptographic signatures, so it must be secured from the start. The standard pattern relies on an access token issued to the ERP system, attached to every request in the authentication header.
There are two practical principles that must be adhered to. The first is separating the test environment from the production environment: each environment has its own tokens, so a test invoice is not sent to the real Fatoora platform by mistake. The second is token rotation: an access token does not stay valid forever, but is renewed periodically, so even if an old token leaks it does not remain valid.
As for the CSID certificate, it is the heart of the signing process, and it is managed by the invoicing layer, not the ERP system. This is a deliberate separation: the ERP system sends the raw invoice data, and the invoicing layer alone holds the certificate and signs with it. This way the secret signing material stays confined to a single place, and its copies do not spread across multiple systems.
The step-by-step sequence of issuing a single invoice from ERP
Before moving on to the design patterns, we trace the journey of a single invoice from the moment it originates in the ERP system until it is cleared. Understanding this sequence clarifies where each responsibility lies.
- Origination: A user in the ERP system confirms a sales order or a shipment, so the system generates an invoice in its internal format with all its fields complete (the customer, the line items, the tax, the totals).
- Sending: The ERP system pushes the invoice data to the invoicing layer over the API, attached with its unique internal identifier to prevent duplication.
- Mapping validation: The invoicing layer verifies the completeness of the mandatory fields, the validity of the tax number, and the matching of the totals before any generation.
- Generation: The UBL 2.1 tree is built with the correct order of elements, and filled with the values after converting units and formats.
- Signing and stamping: The Phase Two-specific values are added: the cryptographic stamp with the CSID certificate, a unique UUID, the hash of the previous invoice to link the chain, and a QR code.
- Sending to the platform: The document is sent to the Fatoora platform for instant clearance (B2B) or recorded for reporting (B2C).
- Returning: The result of the operation is returned to the ERP system: the cleared UUID, the QR code, and the acceptance status, so the ERP system saves them against the original sales order.
The third step is the safety valve. Early validation prevents incomplete invoices from being sent to the platform, and it shortens the correction cycle: instead of the platform rejecting the invoice after a full journey, the problem is detected locally and returned quickly to the ERP system with a clear reason.
Examples of validation messages and how the ERP system interprets them
When an invoice is rejected, the invoicing layer returns an error code and a description. The ERP system integration must understand these codes and handle them instead of displaying them as raw text to the user. Typical examples:
The first code means that the buyer’s tax number is invalid in a standard B2B invoice, so the ERP system directs the user to correct the customer’s data. The second code means that the total does not equal the sum of the line items plus tax, and it is usually a rounding error or a discount field that was not mapped. Translating these codes into understandable messages inside the ERP system shortens the correction time considerably.
Common integration patterns with ERP systems
After years of connecting resource-planning systems to invoicing layers, recurring patterns have crystallized. Knowing them shortens the design time.
The compliance layer pattern (Compliance Layer)
The ERP system stays as it is without deep modification, and a compliant invoicing layer is added as an external service that receives the invoice data and takes care of everything related to Phase Two. This is the most common pattern when connecting a global ERP system that does not understand the requirements of the Zakat, Tax and Customs Authority. Here a local accounting system such as Qoyod acts as the compliance layer.
The two-way sync pattern (Two-Way Sync)
The integration does not stop at sending the invoices, but returns the status of each invoice to the ERP system: has it been cleared? What is the resulting UUID? What is the QR? The ERP system saves these values against the original sales order, so it keeps a complete picture of the compliance status for each document.
The file-based pattern (File-Based)
Some legacy ERP systems do not have a modern API, so they export the invoices as files (CSV or internal XML) to a shared folder. The integration layer monitors the folder, picks up each new file, and converts it into compliant UBL. Slower than direct integration, but it is the realistic solution when modifying the ERP system is impossible.
Reconciliation and monitoring after go-live
Integration does not end at the success of the first batch. In daily operation, the picture of the invoices in the ERP system must remain identical to their picture in the invoicing layer. Any gap between them means an invoice was issued in one system and not recorded in the other, and this is both a compliance risk and an accounting risk.
The recommended practice is a periodic reconciliation that compares two sets: the invoices the ERP system believes it sent, and the invoices the invoicing layer actually cleared. The differences reveal three cases:
- Present in the ERP and absent in the invoicing layer: An invoice that did not arrive or was lost along the way, needing to be resent.
- Present in the invoicing layer and absent in the ERP: Usually an invoice that was cleared but whose result was not saved in the ERP system due to an interruption, needing a status resync.
- Present in both with a value difference: A conflict in the totals or the status, needing a manual check.
Alongside reconciliation, the high-volume enterprise needs real-time monitoring of the integration’s health: the rejection rate, the Fatoora platform’s response time, and the queue depth. A sudden rise in rejections may mean a change in master data or an error in mapping a new field. And an increasing queue depth means the issuance rate is not keeping up with the origination rate in the ERP system, so invoices pile up and clearance is delayed.
These indicators turn into alerts: when the rejection rate exceeds a certain threshold, or the queue fills up, the system issues an alert before the delay becomes a compliance problem. Proactive monitoring is far cheaper than dealing with a stuck batch at the close of the tax period.
Common errors in ERP integration and how to avoid them
- Assuming the ERP system generates ready UBL: Most global ERP systems generate an invoice in their own format, not in the UBL format compliant with Phase Two. The conversion layer is always necessary.
- Sending the same invoice twice: When retrying after an interruption, make sure there is a unique identifier for each document that prevents duplicate issuance.
- Ignoring the order of elements in UBL: The order of elements within the tree is part of the standard. Reordering the fields may cause the platform to reject them even if the values are correct.
- Confusing B2B with B2C: Sending a standard invoice through the reporting path instead of clearance means it is not cleared at all. Classify the invoice type from the ERP system accurately.
- Letting master data diverge: Editing a customer’s data in two places creates conflicting invoices. Make the source of truth a single one.
How Qoyod handles the integration layer
When you connect an ERP system to Qoyod, Qoyod takes care of the parts related to compliance without you writing XML by hand:
- It converts the invoice data coming from your system into a compliant UBL 2.1 document automatically.
- It signs and cryptographically stamps each invoice, and manages the CSID certificate on your behalf.
- It handles the instant clearance of B2B invoices and reporting within 24 hours for B2C invoices with the Fatoora platform.
- It preserves the hash chain between successive invoices to verify the integrity of the sequence.
The ERP system remains the source of truth for your operations, and Qoyod remains the source of truth for your compliance. This clear separation of responsibilities is the essence of a successful and stable integration. For more on the invoicing capabilities, see Qoyod’s electronic invoicing software.
Frequently asked questions
Is Qoyod an ERP system?
No. Qoyod is an integrated accounting system that provides an electronic invoicing layer compliant with Phase Two. When it is connected to an ERP system specific to your enterprise, Qoyod acts as a compliance layer that receives the invoice data, generates the UBL document, and connects it to the Fatoora platform.
Do I need to write XML myself when connecting?
No. The invoicing layer takes care of generating the UBL document automatically from the data the ERP system sends. Your job is to map your system’s fields to the required fields, not to write XML by hand.
How do I handle thousands of invoices a day?
Use the asynchronous queue pattern: the ERP system writes the invoices to a queue, the integration layer pulls them at a rate that respects the Fatoora platform’s limits, and it processes each invoice independently while recording the result. Remember that B2B invoices need instant clearance, and simplified ones are reported within 24 hours.
What is the difference between ERP integration and API integration?
API integration is the specification of the programming interface itself (the endpoints, the authentication, and the formats). ERP integration is a broader scenario that uses that interface to pump the data of a high-volume resource-planning system, with the challenges of field mapping and master data synchronization.
Which system is the source of truth for master data?
Make the ERP system the single source of truth for customer, product, and tax-category data, and make the invoicing layer only a consumer of it. This prevents data divergence and the appearance of conflicting invoices.
What happens if a single invoice in the batch is rejected?
A sound design processes each invoice independently, so the rest of the batch continues to be issued. The rejected invoice alone is returned with its rejection reason to the ERP system, which corrects the reason and resends it without affecting what was successfully cleared.