Egypt ETA E-Invoice & E-Receipt
The ECOSIRE Egypt ETA module is a country pack that connects Odoo to the Egyptian Tax Authority (ETA) e-invoicing and e-receipt system. Egypt operates a direct government API model: your Odoo instance calls the ETA REST API directly (no Peppol relay, no third-party ASP) using OAuth2 client_credentials to obtain a short-lived JWT, then submits signed JSON documents asynchronously.
This module sits on top of the GCC E-Invoicing | Core Engine and adds everything Egypt-specific: the ETA state machine (draft → built → submitted → cleared / rejected), submission UUID and document UUID tracking, cancel/reject within the ETA time window, EGS/GS1 product code management, notification polling, a per-submission audit log, and a clear preprod-first onboarding flow.
Compatibility: Odoo 17 / 18 / 19 (Community or Enterprise) Price: $349 (one-time) — requires GCC E-Invoicing Core ($499) installed alongside License: Up to 3 domain activations Category: Accounting / Localizations / EDI ETA authority: Egyptian Tax Authority — sdk.invoicing.eta.gov.eg
The GCC E-Invoicing suite is live at zatca.demo.ecosire.com — log in with admin / admin. The KSA pack is active on the demo; Egypt pack configuration requires your own ETA preprod sandbox credentials.
Overview
Egypt's ETA mandate covers B2B e-invoicing (Invoice, Credit Note, Debit Note, and Export variants) and B2C e-receipt (POS). The mandate has been rolling out in phases: large taxpayers first, then mid-size, then small taxpayers and B2C eReceipt. Check the ETA portal to verify your filing obligation.
What this module does:
- OAuth2 token management — acquires and caches a 60-minute Bearer token from the ETA Identity Service (
id.eta.gov.eg/id.preprod.eta.gov.eg). Tokens are cached for the full lifetime; the module never acquires a new token on every API call. - Document builder — assembles a JSON document skeleton from an Odoo
account.move: issuer TIN/RIN, receiver identity, document type and version, line items with EGS item codes and unit types, tax breakdown, and totals. - Async submission — posts the document to
POST /api/v1.0/documentsubmissions(HTTP 202 = accepted for processing, not final clearance). The module stores the ETA-assignedsubmissionUUIDand, once assigned,documentUUID(26 chars) andlongId(42 chars, for ETA PDF retrieval). - Submission lifecycle state machine — seven states:
draft → built → submitted → cleared / rejected / pending_retry / dead_letter. Every state change is chatter-logged. - Cancel / reject within ETA window —
PUT /api/v1.0/documents/state/{UUID}/statefor issuers (cancel) and recipients (reject), within the ETA-configured time window. - Poll submission status —
GET /api/v1.0/documentsubmissions/{submissionUUID}to reconcile state after the async 202. - Document type / schema retrieval —
GET /api/v1.0/documenttypesand version schema endpoint (returns Base64 JSON/XML schema) for diagnostic use. - ETA notification polling —
GET /api/v1.0/notifications/taxpayerwith date/type/language filters. - EGS / GS1 product code management — register taxpayer internal codes (
POST /api/v1.0/codetypes/requests/codes) and search published codes. - Automatic retry cron — a scheduled job retries
pending_retrysubmissions (transient 429/503 failures). After five consecutive failures, a submission moves todead_letterfor manual review. - Per-submission audit log (
eta.audit.log) — every API attempt is recorded with HTTP method, target URL, environment, ETA error code, and a truncated response excerpt. Secrets are never written. - Per-company credential scope — credentials live on
res.companyand are company-scoped, supporting multi-company deployments. - Environment switch — preprod sandbox vs production, per company.
Important constraints (sandbox-gated): The exact JSON document schema (field names, casing, required sub-objects) is published by ETA only via the preprod sandbox Get Document Type Version endpoint. The X.509 eSeal signing algorithm and CanonicalJSON serialization rules live in the ETA integration toolkit (Docker/NuGet/CLI), not in public documentation. The eReceipt submission endpoint path was unavailable on the SDK portal at contract-verification time. These three areas raise a clear UserError directing you to complete preprod sandbox onboarding before using them in production. No endpoints are fabricated — only contract-verified paths are implemented.
Requirements
| Requirement | Detail |
|---|---|
| Odoo | 17.0, 18.0, or 19.0 (Community or Enterprise) |
| Required module | ecosire_einvoice_core (GCC E-Invoicing Core Engine) |
| Required module | ecosire_license_client (ECOSIRE License Client) |
| Python packages | requests |
| ECOSIRE license | Active license for ecosire_einvoice_eg |
| ETA preprod credentials | OAuth2 client_id + client_secret from the ETA preprod portal — required before any submission |
| X.509 eSeal certificate | USB hardware security token or HSM from an ETA-accredited certification authority — required for production submissions |
Installation
- Download ECOSIRE GCC E-Invoicing Core and ECOSIRE Egypt ETA E-Invoice ZIPs from your ECOSIRE Dashboard.
- Extract both to your Odoo addons directory:
unzip ecosire-einvoice-core-*.zip -d /opt/odoo/addons/
unzip ecosire-einvoice-eg-*.zip -d /opt/odoo/addons/ - Install the Python dependency:
pip install requests - Restart the Odoo service:
sudo systemctl restart odoo - In Odoo, go to Apps, click Update Apps List.
- Search for ECOSIRE E-Invoicing | Egypt ETA and click Install (the core engine installs automatically as a dependency).
- Enter your ECOSIRE license key when prompted.
After installation an ETA E-Invoicing menu appears under Accounting.
Configuration & Credentials
Step 1: Activate your ECOSIRE license
Navigate to Settings → ECOSIRE License and enter the license key you received. The license must be active before building or submitting documents — all transmission entry points are license-gated.
Step 2: Obtain ETA credentials from the preprod portal
Before configuring Odoo, complete taxpayer-system registration on the ETA preprod portal:
- Go to profile.preprod.eta.gov.eg and register your organization.
- Under the taxpayer-system registration section, create a new system integration and note your Client ID and Client Secret.
- Install the ETA Root CA certificate on your development machine (preprod only — do not install the preprod certificate on production systems). Admin rights are required on Windows.
- Download the ETA Postman collection and environment files from the SDK portal FAQ page to verify your credentials manually before wiring them into Odoo.
- Obtain your Taxpayer Registration/Identification Number (RIN/TIN) — this appears as the issuer identity on every submitted document.
- Procure an X.509 eSeal certificate from an ETA-accredited certification authority (USB token or HSM) — required before signing live production documents. Preprod uses document version v0.9, which disables signature validation for testing.
Step 3: Enter credentials in Odoo
- Go to Settings → Companies and open your company record.
- Open the ETA E-Invoicing tab (added by this module).
- Fill in the following fields:
| Field | Where it comes from |
|---|---|
ETA Environment | Choose Preprod Sandbox first; switch to Production only after successful sandbox tests |
ETA Client ID | OAuth2 client_id from the ETA portal system registration |
ETA Client Secret | OAuth2 client_secret from the ETA portal system registration — stored masked |
ETA Registration Number (RIN/TIN) | Your taxpayer registration/identification number |
On-Behalf-Of (Intermediary) | Leave empty for direct submission; set to the taxpayer RIN only if this ERP acts as an intermediary on behalf of another registered entity |
ETA Document Version | v1.0 for production (signature validation active); v0.9 for transition/testing only (signature validation disabled) |
- Save the company record. Credentials are stored per company — in a multi-company setup, configure each company independently.
Step 4: Verify the connection (preprod)
Open an ETA Submission record (Accounting → ETA E-Invoicing → Submissions → New), select a posted invoice, set Document Type to Invoice, and click Build Document. If credentials and the RIN are correct, the document JSON is assembled and the state advances to Built. Review the JSON in the Document JSON field — this is the contract-shaped skeleton. Full schema conformance and eSeal signing require completing the preprod sandbox integration toolkit setup (see the ETA SDK portal at sdk.invoicing.eta.gov.eg).
Sandbox vs production
| Item | Preprod Sandbox | Production |
|---|---|---|
| Identity service | id.preprod.eta.gov.eg | id.eta.gov.eg |
| API base URL | api.preprod.invoicing.eta.gov.eg | api.invoicing.eta.gov.eg |
| Root CA | Install ETA preprod Root CA (dev machine only) | Standard trusted CA |
| Document version | v0.9 (signature validation off) | v1.0 (signature required) |
| Signing | Not required (v0.9) | X.509 eSeal certificate required |
Switch the ETA Environment field on the company to Production only after you have validated the full flow — schema-exact document assembly and eSeal signing — in the preprod sandbox.
Usage
The submission workflow
Each ETA document starts as an eta.submission record linked to an Odoo invoice (account.move). The workflow is:
- Create a submission — go to Accounting → ETA E-Invoicing → Submissions and click New. Select the posted invoice and choose the document type (Invoice, Credit Note, Debit Note, Export Invoice, Export Credit Note, or Export Debit Note).
- Build document — click Build Document. The module assembles the JSON payload from the invoice (issuer, receiver, line items, taxes, totals) and stores it on the record. State moves to
Built. - Submit to ETA — click Submit. The module posts the payload to
POST /api/v1.0/documentsubmissions. ETA returns HTTP 202 (accepted for async processing) with asubmissionUUID. State moves toSubmitted. - Poll status — click Poll Status to query
GET /api/v1.0/documentsubmissions/{submissionUUID}. When ETA finishes processing, the state advances toCleared(valid) orRejected. - Cancel or reject (if needed) — within the ETA-configured time window, use Cancel (issuer) or Reject (recipient) to send a
PUTstate-change request. After the window expires, issue a credit note instead.
Submission states
| State | Meaning |
|---|---|
| Draft | Record created; no document built yet |
| Built | JSON document assembled; not yet submitted |
| Submitted | Accepted by ETA (HTTP 202); awaiting async processing |
| Cleared | ETA confirmed the document is valid |
| Rejected | ETA rejected the document (see audit log for error code) |
| Pending Retry | Transient failure (429/503) — automatic retry cron will re-attempt |
| Dead Letter | Five consecutive failures — manual review required |
Automatic retry
A scheduled cron job (_cron_retry_pending) runs on the interval configured in Settings → Technical → Automation → Scheduled Actions and re-attempts all pending_retry submissions. After five failures, the submission moves to dead_letter. The retry cron silently skips execution if the ECOSIRE license is not active.
Audit log
Every API interaction is recorded in eta.audit.log (Accounting → ETA E-Invoicing → Audit Log): HTTP method, target URL, environment (preprod/production), outcome, ETA error code, and a truncated response excerpt. Credentials and secrets are never written to the audit log.
ETA notification polling
Go to Accounting → ETA E-Invoicing → Notifications and use Poll Notifications to query GET /api/v1.0/notifications/taxpayer. You can filter by date range, notification type (1–9), and language (Arabic or English).
EGS product code management
If your products use internal EGS codes, register them with ETA via Accounting → ETA E-Invoicing → EGS Codes → Register Code. ETA employee approval is required before the code can be used in submissions. Use Search Codes to browse published GS1 and EGS codes.
Troubleshooting / FAQ
| Issue | Cause and fix |
|---|---|
| "ETA credentials missing" | The company's ETA Client ID or Client Secret field is empty. Go to Settings → Companies → ETA E-Invoicing tab and fill both fields. |
| "Set ETA Registration Number before building" | The company RIN/TIN field is empty. Set ETA Registration Number (RIN/TIN) on the company. |
| License not active | The ECOSIRE license for ecosire_einvoice_eg is missing or expired. Go to Settings → ECOSIRE License and verify the key. |
| HTTP 400 BadStructure | The document payload does not match the ETA JSON schema. This occurs before you have completed the schema-exact assembly via the ETA integration toolkit. Verify the document JSON against the schema retrieved from the sandbox Get Document Type Version endpoint. |
| HTTP 400 MaximumSizeExceeded | The submission payload is too large. Split into smaller batches. |
| HTTP 403 IncorrectSubmitter | The authenticated client_id does not match the issuer TIN. Confirm the credentials belong to the same taxpayer system registration as the RIN on the company. |
| HTTP 422 DuplicateSubmission | An identical document was submitted within the last 10 minutes. Wait and check whether the original was accepted. |
| HTTP 429 / submission in Pending Retry | Rate limit exceeded. The automatic retry cron handles this. ETA recommends following the Retry-After header. |
| HTTP 503 / submission in Pending Retry | ETA system overload. Retry after 1–3 seconds; the cron handles this automatically. |
| "X.509 eSeal signing algorithm — sandbox required" | The document signing step is gated. Complete the ETA preprod sandbox onboarding using the ETA integration toolkit (Docker/NuGet/CLI). |
| "eReceipt endpoint path is not verified" | The eReceipt submission path was unavailable in the SDK portal at contract-verification time. Complete preprod sandbox access to obtain the verified path before using eReceipt submission. |
| State stays at Submitted | ETA processing is asynchronous. Click Poll Status a few minutes after submission. Use the ETA invoicing portal (invoicing.eta.gov.eg) to confirm document status independently. |
| Rejection after time window | You can no longer cancel. Issue a credit note in Odoo and submit it as a Credit Note document type. |
| Preprod SSL errors | You have not installed the ETA preprod Root CA certificate. Follow the instructions at sdk.invoicing.eta.gov.eg/faq/ — admin rights are required on Windows. Do not install the preprod cert on production machines. |
Why does the document say production_ready: false?
The document builder produces a skeleton whose top-level shape is grounded in the ETA contract (issuer, receiver, type, lines, totals). The schema-exact field names and eSeal signature are added by the ETA integration toolkit during the preprod phase. The _ecosire_meta.production_ready: false flag in the built JSON is a safety marker that tells you the skeleton is ready for review but must pass through the toolkit signing step before live production submission.
Can I use this module without the GCC E-Invoicing Core?
No. ecosire_einvoice_core is a required dependency and must be installed first.
Does this module support eReceipt (B2C POS)?
The eReceipt submission endpoint paths were unavailable in the ETA SDK portal at the time the API contract was verified (June 2026 — detail pages returned 404). The POS submission path is stubbed with a clear error message. Once the paths are confirmed via preprod sandbox access, they will be implemented. eInvoicing (B2B documents) is fully wired.
What is the ETA document version?
v1.0 is the production version (signature validation active). v0.9 has signature validation disabled and is a transition/testing version only. Always use v1.0 for production submissions.
Support
- Related module: GCC E-Invoicing | Core Engine
- ETA developer portal: sdk.invoicing.eta.gov.eg
- ETA taxpayer portal (production): profile.eta.gov.eg
- ETA taxpayer portal (preprod): profile.preprod.eta.gov.eg
- General Troubleshooting
- Email: [email protected]
- Support Portal