The gap between a payment gateway and an invoicing system is where duplicate tax documents come from. One decision closes it, plus the queue design and reconciliation that make the automation trustworthy.
Key takeaways
- One side issues the document. If the gateway is configured to issue and your system also issues, one transaction produces two tax documents - and it surfaces at month end, not in testing.
- Trigger on the server notification, never on the browser return. A customer who closes the tab after paying never reaches your page, and the invoice never gets issued.
- Issue asynchronously through a queue. Putting document creation inside the payment callback means a slow invoicing service turns into failed payments.
- A daily reconciliation between payments and documents is what makes this trustworthy. Without it, a silent gap becomes an accounting problem discovered weeks later.
A customer paid, and a tax document has to be issued. It sounds like a simple connection between two systems, and it is the seam that produces more accounting problems than any other in the Israeli stack. The reason is almost always the same: nobody decided explicitly who issues the document.
The decision that closes the problem
There are three ways to issue a document after payment, and only two are correct:
| Who issues | When it fits |
|---|---|
| The gateway - configured to issue automatically | Simple transactions: one amount, one item, no business logic |
| Your system - calling the invoicing system | When you need control: line detail, discounts, document-type logic |
| Both | Never. This produces two tax documents for one transaction |
That third row is not theoretical - it is the most common mistake in these projects. It happens because the gateway was configured to issue a document during its own setup, before the project began, and nobody checked. The new code adds its own issuance, and in testing everything looks fine - because people look at the order, not at the invoicing system.
It surfaces at month end, at the accountant's desk. And then tax documents have to be cancelled one by one with offsetting documents.
The first check in any such project: open the gateway's settings and see whether automatic issuance is enabled. Do not ask - look.
The trigger: a server notification, not the browser
Having decided who issues, the second question is what triggers it.
Not the browser return. This recurs in every gateway guide for good reason: a customer who closes the tab the moment payment clears, whose connection drops, or who simply does not wait, never reaches your thank-you page. If that is where issuance is triggered, the customer paid and received no invoice.
And that is worse than an order stuck as "pending": a missing invoice is an accounting problem, not just a user-experience one.
Issuance is triggered from the gateway's server-to-server notification. The browser shows a thank-you screen and nothing more.
The structure that works
The second-largest mistake is calling the invoicing system from inside the payment callback itself. Two external systems in one chain, and if the second is slow, the first times out and assumes failure.
The correct structure:
- The payment callback arrives. Verify it genuinely came from the gateway, cross-check the amount against the order.
- Mark the order paid and write a job to a queue. Respond immediately.
- A separate worker processes the queue - calls the invoicing system, receives a document, stores the id and link on the order.
- Failures stay in the queue with controlled retries, and after several attempts move to an error queue a human sees.
The benefit: a slow or unavailable invoicing system delays the invoice but does not break the payment. And that is the right order - the money lands, the document follows.
Duplicate protection
Even with one side issuing, you can still get two invoices. Two sources:
- A duplicate callback. Gateways redeliver notifications. If every notification enqueues a job, there are two jobs.
- A timeout that succeeded. You called the invoicing system, got no response, retried - and the first document had been created.
The two defences:
- A unique key on the job - the order id or transaction id. The same order does not enter the queue twice.
- Before any retry, check whether the document already exists. A
timeoutis not a failure - it is an absence of knowledge. A missing document is fixed in a minute; a duplicate tax document needs a cancellation and a paper trail.
What has to travel from the payment to the document
A point easy to miss: the gateway knows how much was charged, but not necessarily what was sold.
If the document needs line detail - items, quantities, discounts - that information lives in your order, not in the gateway's response. So the queued job should carry the order id, and the worker pulls the detail from it.
And two things requiring the accountant's decision rather than the developer's:
- Which document type. Tax invoice, combined invoice-receipt, receipt - the choice determines when revenue is recognised.
- Instalment transactions. Does the document reflect the full amount or the instalment? See Grow for detail.
Daily reconciliation - what makes this trustworthy
Automation without reconciliation is an optimisation, not a system you can rely on.
A job that runs daily and compares: every payment received yesterday - does it have a document? Any gap raises an alert.
It is cheap to build, roughly a day's work, and it is what catches whatever the queue missed - a lost callback, a stuck job, a failure nobody saw. In an accounting context this is not a luxury, because a missing invoice discovered two months later is a considerably bigger problem than one discovered the next morning.
Checklist
- Check the gateway settings for automatic issuance - before writing a line.
- Decide who issues, and document it.
- The trigger is the server notification, not the browser.
- Asynchronous issuance through a queue, not inside the callback.
- A unique key on the job plus an existence check before any retry.
- Get in writing from the accountant: which document type, and how an instalment transaction is recorded.
- An error queue a human checks each morning.
- Daily reconciliation between payments and documents.
Related: the Israeli invoicing API comparison · allocation numbers and your system.
Frequently asked questions
Why do some transactions end up with two tax documents?
Because the payment gateway was configured to issue a document automatically - often during its own setup, before the project began - and the new integration issues one as well. It passes testing because people check the order rather than the invoicing system, and surfaces at month end. The first check in any such project is to open the gateway settings and look, rather than asking.
Should invoice issuance be triggered on the payment redirect?
No. The browser return depends on the customer staying on the page, and anyone who closes the tab as soon as payment clears never reaches it - so they paid and received no invoice. That is an accounting problem rather than a user-experience one. Trigger issuance from the gateway's server-to-server notification and use the redirect only for a thank-you screen.
Should the invoicing system be called from inside the payment callback?
No - use a queue. Chaining two external systems in one request means a slow invoicing service causes the payment callback to time out and be treated as failed. Mark the order paid, enqueue a job, respond immediately, and let a separate worker create the document with controlled retries. A slow invoicing system should delay the invoice, not break the payment.
How do you prevent duplicate invoices in an automated flow?
Two defences. Put a unique key on the queued job - the order or transaction id - so the same order cannot be enqueued twice when a gateway redelivers a callback. And before any retry against the invoicing system, check whether a document already exists, because a timeout means you do not know whether the first attempt succeeded.
Why does a payment-to-invoice automation need daily reconciliation?
Because queues lose things quietly - a callback that never arrived, a job that stalled, a failure nobody saw. A daily job asking whether every payment received yesterday has a corresponding document is roughly a day to build and catches all of those. In an accounting context that matters: a missing invoice found the next morning is a much smaller problem than one found two months later.
Keep reading
Related service
Integrations
Make the systems you already pay for talk to each other.
About the author
Yehonatan Saadia
Freelance automation, web & MVP engineer
I'm Yehonatan Saadia, a senior engineer who builds business automation, custom websites, and MVPs for small and mid-sized companies across the US, Europe, and Israel. These guides come from real client work, not theory.
Work with meHave a project like this?
Tell me what you're trying to automate or build and I'll tell you the fastest reliable way to ship it.
