Preparing a Legacy System for Israel Invoice Without Replacing It
Back to blog
full stack·September 5, 2026·4 min read·By Yehonatan Saadia

Preparing a Legacy System for Israel Invoice Without Replacing It

An older invoicing system can keep running when an allocation number is required. What it is missing, which fields to add, and how to build the middle layer.

Key takeaways

  • The usual gap is three missing columns on the document record, not a new engine: an `INVOICE_ID`, the allocation number received, and a call status.
  • Per the specification, the reference number becomes a mandatory value from 2025, and the call is made once the invoice already carries that reference number.
  • A middle layer that reads from the legacy system and calls the service lets the old issuing code stay substantially untouched.
  • Authentication is OAuth2, so the legacy host needs outbound HTTPS and a safe place to hold secrets.
  • Printing becomes the last step in the flow rather than the first, and re-ordering those steps is most of the work.

An older system that issues invoices does not have to be thrown away to work against the allocation-number service. The gap is almost always a data gap rather than an architectural one: a missing unique identifier, a missing column for the number that comes back, and a missing pause in the flow before printing.

This is a technical description of an architecture and of data fields, not tax, legal or accounting advice.

What the older system is actually missing

Systems built before online invoicing issue a document and print it in the same action. There is no pause between them that waits for an external answer. That structure is what has to be taken apart, and it is also the only part that genuinely touches the old code.

At the data level, these are the columns that are almost always absent from the document record:

  • A stable unique identifier for the call, written before the first request rather than generated at print time.
  • A column for the allocation number received, separate from the internal document number.
  • A call status: not sent, sent, approved, not approved, alternative chosen.
  • A timestamp for the last call and an attempt counter.
  • The customer's VAT number, populated and well formed, rather than free text sitting inside a name field.

That last one sinks more old databases than anything else, because in many systems the customer's VAT number lives as text beside the name, or does not exist at all. Structural validation of Israeli identifiers before they reach an interface is covered in validating Israeli ID and company numbers in forms.

Can allocation be added without touching the legacy system?

Almost. The practical shape is a separate middle layer between the legacy system and the service, but it cannot be entirely transparent: something has to hold the allocation number and the status, and something has to stop the print. Both of those touch the source system.

What can stay untouched: pricing logic, internal document numbering, reports, and everything around them. The layer reads the document record, builds the request body, calls the service, writes two columns back, and returns a binary answer to the issuing screen.

ComponentStays in the legacy systemMoves to the middle layer
Internal document numberingYesNo
Building the request bodyNoYes
Authentication and token handlingNoYes
Storing the allocation numberYes, in a new columnNo
Retries and backoffNoYes
The user's choice of alternativeThe issuing screenRecorded and transmitted
PrintingYes, at the endNo

The order of operations that changes

  • The document is saved with its reference number before the call, because per the specification the call is made once the invoice already carries that reference number.
  • The request goes out with a unique identifier and the document fields.
  • The response is inspected on its output fields, not on the HTTP status code alone.
  • The allocation number is stored on the record, and only then is the document printed.
  • If no number came back, the screen presents the alternatives and the choice is recorded.

One further separation saves a lot of pain: waiting, retrying and backing off are not the issuing screen's job. If the service is slow, the screen should show a state rather than freeze, and the system should be able to resume from where it stopped.

What happens to Access systems and old files

Older databases add difficulties of their own. Dates stored as free text will not translate into the YYYY-MM-DD format the specification defines for date fields. Numeric values stored as strings will pass or fail schema validation depending on what somebody typed a decade ago. Legacy Hebrew encoding can turn a customer name into noise inside a JSON body.

So the first step is an exceptions report over the existing data, not writing code: how many documents have no customer VAT number, how many dates cannot be parsed, how many amounts are negative in unexpected places. If the system is on its way out anyway, read the Access to web system migration plan before investing in a layer you will discard.

How do you test this without risking real invoices?

The specification defines two environments: a production address and a testing address under tsandbox. The first pass runs against the test environment, using data from the real system but in a separate runtime.

  • A completely valid document, to prove authentication and request shape.
  • A document with a bad VAT number, to prove the code recognises a content error.
  • A negative response, to prove the screen does not print.
  • A connection dropped mid-call, to prove the document does not end in an unknown state.
  • A repeat call with the same identifier, to prove nothing is duplicated.

What to decide before writing a line of code

Most of these projects stall on operational decisions rather than on integration. Settle them up front, because each one changes the implementation.

  • What happens when the service is unreachable: does issuing stop, or continue and get flagged for handling.
  • Who in the business is authorised to choose an alternative when no number came back, and what happens when that person is out.
  • Whether the new flow applies to every document type or only to some.
  • How long the screen waits before showing a message, and how many retries are attempted.
  • Who is alerted when documents pile up in a non-final status.

The first decision is the heaviest and it is not an engineering one. A system that stops issuing when the network is down protects data integrity and shuts the counter. A system that continues keeps the business running and creates a queue of documents needing attention. Both are defensible, but one has to be chosen and written down, because otherwise it gets decided in practice by whatever happens to be in the code.

What this does to the detailed VAT report

The new column does not stay inside the system. The specification defines a "short allocation number" - the last nine characters - required on the transaction record in the detailed report, on both the sales and the input side. Every change made in the issuing layer therefore has to reach the code that produces the report file, or you end up with a system that issues correctly and reports partially. Full background on that file is in automating VAT reporting in Israel.

Sources

#Israel Invoice#legacy systems#Access#integration#middleware#חשבונית ישראל

Frequently asked questions

Do I have to replace the system to work with the service?

Not necessarily. The main gap is columns on the document record and a pause before printing. A system you can add three columns to, and whose issuing order you can change, can work against the service through a middle layer without touching pricing or reports.

Where do the credentials live?

The specification sets OAuth2 authentication, which means a token that has to be current. It does not belong in the legacy system's configuration file or in code. The middle layer is the natural place to hold it, refresh it, and return a clear error when it is not valid.

What about invoices already issued?

Invoices issued before the connection do not change state retroactively because a new layer exists. What you do need is a decision about the date from which the system moves to the new flow, and confirmation that the reporting code handles both periods inside one file.

How much work is this in practice?

Most of the time goes on data rather than code: cleaning customer VAT numbers, normalising dates, and deciding what happens when no answer arrives. The connection itself is one authenticated HTTP call. The exceptions report over existing data is what sets the schedule.

Keep reading

Related service

Access & Excel Rescue

Stabilise the file the business runs on, then fix it or move it to the web.

Learn more →←

About the author

Yehonatan Saadia

Freelance automation, web & MVP developer

I'm Yehonatan Saadia, a senior developer 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 me

Have a project like this?

Tell me what you're trying to automate or build. I reply within 24 business hours with a few targeted questions, then we walk through it on a free 30-minute call, with no commitment. You come away with a scope, a timeline and a fixed price - or a straight answer that it isn't worth building.