Connecting Odoo to the Egyptian Tax Authority: a checklist before you file
TechnoVision
24 September 2026 · 8 min read
Most failed Odoo–ETA go-lives are not caused by code. They are caused by a missing EGS code, a token plugged into the wrong machine, or a Client Secret generated for preprod and pasted into production. This checklist collects everything that has to be true before the first real invoice leaves Odoo, in the order you should do it.
It applies to Odoo 17, 18 and 19, Community or Enterprise, and to any integration module, including your own. Where the ETA's own rules could change, we say "check the current ETA guidance" rather than guess.
Overview: the six things that must exist
| # | Item | Who provides it | Where it lives in Odoo |
|---|---|---|---|
| 1 | Taxpayer profile with branches and activity codes | ETA portal | Company form |
| 2 | ERP registration: Client ID and Client Secret | ETA portal (per environment) | ETA configuration |
| 3 | Signing certificate on a USB token or HSM (eSeal) | Licensed certificate provider | Signing service next to Odoo |
| 4 | Approved item codes (GS1 or EGS) for every product | GS1 Egypt / ETA portal | Product form |
| 5 | Unit-of-measure codes mapped to ETA unit types | ETA code tables | UoM form |
| 6 | Customer tax data (RIN, national ID, type) | Your customers | Contact form |
If any row is empty, stop and fill it. Nothing else will work.
Step 1: Get the taxpayer profile right
Before touching Odoo, open your company's profile on the ETA invoicing portal and confirm:
- Tax registration number (RIN) matches exactly what you will put on the Odoo company.
- Branches. Every Odoo company or warehouse that issues invoices must correspond to a branch registered on the profile with a branch ID. The document's
branchIDand issuer address are validated against this. - Activity codes. The
activityCodeon every document must be one of your registered tax activity codes. Pick the primary one for invoices and note it down. - Address fields. Country must be
EG, and governorate, city, street and building number must be filled. Odoo's single "street" field is often not enough; you may need a dedicated building-number field.
Step 2: Register the ERP and obtain Client ID and Secret
The ETA identifies your integration by a Client ID and Client Secret created under ERP in the taxpayer profile. Notes that save hours:
- There are separate environments. Preprod uses
https://id.preprod.eta.gov.egfor identity andhttps://api.preprod.invoicing.eta.gov.egfor the API; production uses the production hosts. Credentials from one do not work on the other. - The secret is shown once. Store it in Odoo's system parameters or a secrets manager, not in a chat message.
- The token endpoint is the identity service's
/connect/tokenwith the client-credentials grant. Tokens expire; your integration must refresh them rather than cache one forever. - Each registered ERP can be limited to specific branches. If you get
403 IncorrectSubmitter, this is the first place to look.
Create one ERP registration per Odoo database, not per user.
Step 3: Sort out signing (eSeal)
Every document must carry a CAdES-BES signature made with a certificate issued by a licensed Egyptian provider. The private key lives on a USB token or HSM, which means:
- Odoo cannot sign in pure Python on a cloud server. You need a small signing service running on a machine where the token is physically plugged in (a Windows box in the office, or an HSM the provider gives you access to).
- The signing service must sign exactly the canonicalised document content, excluding the
signaturessection. If the integration re-serialises the JSON after signing, the signature breaks. - Check the certificate expiry date and put it in your calendar. An expired certificate produces Invalid documents with no obvious warning.
If your module says it "signs invoices", ask where the token is and which service talks to it.
Step 4: Item codes — GS1 or EGS for every product
This is the step that most often delays a go-live. Every invoice line needs a codeType and an itemCode.
| GS1 | EGS | |
|---|---|---|
| Who issues | GS1 (global barcode) | You, on the ETA portal |
| Cost | Paid membership | Free |
| ETA approval | Not needed | Required; GS1 Egypt guidance mentions up to 15 days |
| Uniqueness | Globally unique | Tied to your RIN, may repeat across companies |
| Best for | Physical goods that already have barcodes | Services and internal SKUs |
Practical advice:
- Export your active products from Odoo and decide, per product, GS1 or EGS.
- For EGS, link each code to a GPC (Global Product Classification) category, register it on the portal, and wait for approval. Do this weeks before go-live.
- Store the code type and code on the product form in Odoo, and make both required for saleable products.
- Run a report of products without codes before every submission batch.
Do not submit a real invoice with a code that is still Pending. It will come back Invalid.
Step 5: Unit-of-measure codes
The unitType on each line must come from the ETA's unit code table (for example EA for "each", KGM for kilogram; check the current ETA code list for the exact values). Odoo's UoM names are free text, so you need a mapping:
- Add an "ETA unit code" field on
uom.uom. - Map every UoM used on saleable products.
- Treat an unmapped UoM as a blocking validation error, not a warning.
Step 6: Customer data
The receiver section depends on the customer type:
- B (business): needs the customer's RIN and name.
- P (natural person): ID, name and address are optional below the legal threshold and mandatory above it. The threshold changes; check the current ETA guidance.
- F (foreigner): needs an identifier and country.
In Odoo, add a "receiver type" on the contact, require the RIN for businesses, and validate the national ID format (14 digits) for persons. Enforce these at invoice posting time so accountants find out before filing, not after.
Step 7: Test in preprod first
Never test on production. The ETA's preprod environment mirrors production:
- Install the preprod root CA certificate on the machine that calls the API (the SDK FAQ explains this, and warns not to install it on production machines).
- Register a separate ERP in your preprod profile to get preprod credentials.
- In Odoo, point the integration at the preprod hosts and use a database copy.
- Submit a small set of invoices that cover: a business customer with RIN; a natural-person customer below the threshold; a line with a percentage discount and a non-round unit price; a line in a non-default UoM; a credit note referencing the invoice.
- Poll status until every one is Valid. A 202 is not a pass; see our article on what 202 really means.
- Deliberately break one invoice (wrong item code) and confirm the error is visible in Odoo, in words a human can act on.
Only when all six scenarios return Valid do you switch to production credentials.
Step 8: Decide who presses the button
Automatic submission on invoice posting sounds convenient. It also means a wrong price gets filed with the tax authority before anyone reads it. Our recommendation for Egyptian SMEs:
- Post in Odoo as usual.
- Submit to the ETA deliberately, by a named person, in batches, after a review.
- Keep the right to submit in a dedicated Odoo group so only accountants have it. (Our article on Odoo access rights covers how.)
Pre-flight checklist (copy this)
- Company RIN, branch ID, activity code and full address entered in Odoo and matching the ETA profile.
- Preprod Client ID/Secret tested; production Client ID/Secret stored securely and not yet used.
- Signing service reachable from Odoo; token plugged in; certificate expiry recorded.
- 100% of saleable products have an approved GS1 or EGS code.
- 100% of UoMs on those products mapped to ETA unit codes.
- Customer forms require RIN for businesses and national ID above the threshold.
- Six preprod scenarios returned Valid.
- Error text from
validationStepsis displayed on the invoice. - Submission right limited to a specific user group.
- Someone owns the daily "anything still Submitted or Invalid?" check.
Frequently asked questions
Do I need Odoo Enterprise to connect to the ETA?
No. The ETA API is a plain HTTPS/JSON API. Community and Enterprise can both integrate, provided the module you use supports your edition and you have a signing service for the USB token or HSM.
Can Odoo sign the invoice by itself?
Not on its own. The private key sits on a hardware token or HSM. You need a signing component that has access to that hardware; Odoo sends the document to it and receives the signature back.
What is the difference between GS1 and EGS codes?
GS1 codes are global barcodes you buy from GS1; the ETA accepts them without approval. EGS codes are free codes you register on the ETA portal under your tax number; they must be approved by the ETA before use.
How long does ETA approval of an EGS code take?
GS1 Egypt's guidance mentions up to 15 days. Timing can change; check the current ETA guidance and register codes well before go-live.
If you'd rather not build this yourself