Bulk invoice submission getting blocked need guidance on rate limits and best practice

@Ankit.K.Tiwari @idaoud @Majd_Alawadi
Hello

We are integrating with ZATCA e invoicing API from our ERP system and facing an issue during bulk invoice submission

Our current flow is as follows

A user selects multiple invoices from the system
We generate an array of invoice ids
Then we loop through each invoice
For each invoice we generate XML and submit to ZATCA API
There is no delay between requests
Only API timeout is set to 30 seconds

When the number of invoices is high around 100 to 300 submissions at once we are seeing failures or blocking behavior

We are not sure if this issue is caused by
ZATCA server rate limiting or blocking
or our hosting provider firewall or connection limits since we are using shared hosting and the same IP is used by multiple softwares

We need clarification on the following points

  1. Does ZATCA enforce any rate limits per IP or per taxpayer
  2. Is there any recommended number of requests per second
  3. Is sending many invoices in a loop without delay considered incorrect usage
  4. Is there any guidance for bulk invoice submission from ERP systems
  5. Should we introduce delay or throttling between requests
  6. Is there any recommended architecture for handling bulk submissions

Our goal is to ensure compliance and avoid being blocked while maintaining system performance

Any official guidance or best practices from ZATCA team or other developers would be very helpful

Thank you

What manner of failure do you encounter?

Our cloud-based system serves numerous Taxpayers without issue. Allow me to elucidate our operational protocol: For simplified invoices, an XML file is generated, a requisite step for producing the QR code to be printed on the buyer’s physical copy. We retain this file, and the invoice is subsequently queued for background reporting. The reporting mechanism employs a retry strategy in the event of failure; however, if failures persist and the error code is 503, the system ceases further transmission attempts due to service unavailability. This ensures server resources are not unnecessarily consumed while the service remains inaccessible. A specific algorithm governs the retry process.

@mnuaimi
Thank you for your detailed explanation, that helps clarify your approach.

In our case, the setup is slightly different and might be contributing to the issue. We are currently using a shared hosting environment where multiple ERP systems (belonging to different companies/taxpayers) are deployed on the same server. Although each ERP has its own domain, all outbound API requests are routed through the same public IP address.

Additionally, each of these systems can independently trigger bulk invoice submissions (100–300 invoices) at roughly the same time, which means a high number of requests may be hitting the ZATCA API concurrently from the same IP.

Because of this, I suspect the failures or blocking behavior we are experiencing could be related to IP-based throttling, connection limits, or firewall restrictions—either from the hosting provider or on the ZATCA side.

I wanted to ask:

  • In your implementation, are you operating from a dedicated server/IP, or do you also have multiple systems sharing the same IP?
  • Have you observed any issues related to concurrent bulk submissions from different tenants?
  • Do you apply any request throttling, batching, or queue management (e.g., limiting requests per second) to avoid overwhelming the API?

We are considering introducing a queuing mechanism with controlled throughput and retry logic (especially for 503 responses), but wanted to understand how others are handling similar multi-tenant scenarios.

Appreciate your insights.

@arjun_tech24, Welcome,
We use a single server for multiple taxpayers, and all invoices go through a single queue.

Each queue only processes one invoice at a time. This mechanism allows us to report invoices as soon as they are saved, so the time an invoice spends in the queue is very short thanks to direct delivery.

In your case, you should check your hosting provider’s allocated bandwidth out, as I believe this is the cause of the problem if it’s limited.

The most effective solution for you is to prevent invoices from piling up; ideally, you should report invoices immediately after they are saved.

@mnuaimi
Thanks for the clarification.

In our client’s business scenario, invoices are not required to be reported immediately after creation. They operate on a B2C model where invoices are generated throughout the day and then submitted in bulk at the end of the day.

Because of this operational flow, real-time reporting isn’t aligned with their process. That’s why we implemented a bulk invoice connection approach—to match their business requirements and ensure efficiency on their side.

Based on the above:
The invoice’s business model is B2C.

When saving an invoice, do you generate a QR code for it?

If yes, then you are already creating an XML file for it, and since the invoice cannot be deleted or modified, you can report it.

If no, how do you provide the printed copy to the buyer without a QR code? Therefore, it is necessary to generate an XML file to obtain the QR code, which essentially contains information that you cannot provide without creating an XML file, such as the invoice hash and signature.

This is also necessary to be able to use the invoice hash as a PIH in the next invoice.

The final question: Are the invoices issued from a point of sale separate from the server, and then transferred to the server?

Hi dear collegues,

We are using the same strategy as @mnuaimi , reporting as soon as they arrive, sure you can keep B2C till the end of the day, but these invoices are already prepared (XML) and cannot be tampered (otherwise the Current Invoice Hash) and PIH will not match later on.

We also have the ability to report in bulk, like 1000, we have multiple onboarded devices (I forgot their name) and in round-robin way we are creating invoices to be reported on behalf of this or that device, Like we split the logic and then creating the tasks in the queue…

Note that every DEVICE has it’s own chain of hashes, therefore it can be parallelized. If you have only one device, you cannot queue in parallel, you have to do it sequential…
Also you have to have a blocking mechanism for device as his current hash and PIH should not be used by multiple threads/workers at the same time…

Eventually all these documents are getting into the queue which is just reporting queue, it does not care from which customer or which device it is coming from as it has the FULL xml and can be rerported independently even out of order.

Then we have the same retry logic, if it is 5xx error ,we are scheduling retry in exponential manner with DLQ capabilities which we investigate and retry later if required.

NOTE: if you expect some blocking - you have to at least provide what kind of error messages you are receiving and from where they are… maybe they are from your provider’s gateway…

– Sergei