Fiscalise Odoo invoices to URA EFRIS, automatically
Confirm the invoice in Odoo as you already do. It is submitted to EFRIS, and the fiscal document number, verification code and QR code come back onto the invoice — and onto the PDF your customer receives. Nobody re-keys anything into the URA portal.
Where your Odoo is hosted changes what is possible
Worth settling first, because it decides one thing that matters daily: whether an invoice can be stopped before it is posted, or is fiscalised just after. Both work; they do not feel the same to the person doing the invoicing.
Odoo.sh or self-hosted
A module is installed inside Odoo, so fiscalisation happens as part of confirming the invoice. If URA rejects it, the posting stops and the person raising it is told why, then and there — no document goes out unfiscalised and nobody finds out days later.
The fiscal fields sit on the invoice itself and print on the standard PDF layout, so the document your customer receives is the one they expect.
Odoo Online
Odoo's own hosted edition does not accept custom modules, so the connection is made from outside over Odoo's external API. Invoices are picked up as they are confirmed and the fiscal details written back onto them.
The trade-off is that a rejection cannot block the posting — it is reported straight away and corrected with a credit note. If that is not acceptable for how you invoice, moving to Odoo.sh is the usual answer, and it is a hosting change rather than a migration.
What comes across
EFRIS needs more than the invoice itself. These are read from Odoo and kept in step.
Customer invoices
Fiscalised to EFRIS on confirmation, with the fiscal document number, verification code and QR code returned onto the invoice and its printed layout.
Credit notes
The reversal is raised against the original invoice, which URA requires — a credit note detached from its invoice is rejected.
Products and services
Registered with URA through the API as part of the integration, carrying their unit of measure and tax treatment. Nothing is keyed in by hand.
Stock movements
For goods: opening stock and subsequent movements, which URA requires before those goods can be invoiced. Services carry no stock.
Contacts
Buyer type and TIN where the sale is business-to-business, read from the customer record, which changes what EFRIS requires on the document.
Taxes
Standard-rated, zero-rated, exempt and deemed VAT, plus excise duty where it applies — resolved from your Odoo tax records, including price-included ones.
Where Odoo and EFRIS disagree
The connection is not the difficult part — Odoo is the most open system on this list. Reconciling how the two think about a sale is, and it is where in-house attempts usually stall.
Odoo has three product types. EFRIS has two
Odoo separates storable products, consumables and services; URA separates goods from services and expects stock reported for goods. A consumable is a good as far as URA is concerned but carries no stock in Odoo, so there is nothing there to report — and it is precisely those lines that come back rejected for having no stock against them. The split has to be decided against URA’s definition, not Odoo’s.
Tax-included prices have to be unwound
Odoo will happily hold prices with the tax already inside them, which is normal for retail. EFRIS wants the unit price and the tax stated separately, and it recomputes both. Unwinding an inclusive price introduces rounding at exactly the point where EFRIS is least forgiving, so it is done deliberately rather than left to whatever the report shows.
An item valid in Odoo can still be unknown to URA
A product has to exist in the EFRIS catalogue before an invoice can mention it, and its unit of measure must come from URA’s own list rather than from Odoo’s units, which are freely defined per category. Registration happens through the API — one of the first calls an integration makes — so this is handled, not typed in somewhere.
Discounts are a separate line, not a column
Odoo puts a discount percentage on the line it reduces. EFRIS will not accept that — the discount must follow as its own negative line, flagged as the discount and carrying no quantity at all. A quantity there is rejected outright.
One database, several companies, one TIN
Odoo’s multi-company support is a strength, and it numbers invoices by journal within each company. EFRIS enforces uniqueness of the seller reference per taxpayer, across every till and every integration on that TIN, so two companies invoicing under the same TIN will collide — and the rejection reads as a duplicate submission rather than as a sequence problem. Where the companies are genuinely separate taxpayers, each needs its own EFRIS credentials and device.
Each of these is a rejection code we have already worked through. The error-code reference documents them, free to read, whether or not you ever work with us.
Two ways to do this
Most businesses want the first. Odoo partners and teams with their own Python developers usually want the second.
We set up the environment and everything your business needs to start issuing fiscalised invoices. You keep working in Odoo exactly as before.
Talk to usSend invoices to our API as ordinary JSON and it handles the EFRIS protocol, the signing and the tax reconciliation — your module stays a few hundred lines of Odoo, not a fiscalisation project. Or licence the whole platform as source and run it on your own infrastructure.
efrisgateway.comOdoo and EFRIS — common questions
Can Odoo connect to URA EFRIS?
Does it work on Odoo Online, or do I need to self-host?
Which Odoo versions are supported?
Will the QR code appear on the invoice PDF?
What happens when URA rejects an invoice?
Do I need to be a URA-accredited integrator to use this?
Running something else?
The EFRIS side is identical whatever you run. What changes is how the invoice leaves your system, so each has its own notes.
QuickBooks
Online and Desktop
Tally
TallyPrime and Tally.ERP 9
Sage
Pastel, Evolution, 300, X3
Zoho Books
Cloud, over the Zoho API
A custom ERP, an in-house system or a POS nobody has heard of is not a problem either — if it can produce an invoice, it can be connected. Tell us what you run.
