E-Invoicing | Jordan JoFotara (ISTD)
The ECOSIRE Jordan JoFotara module connects Odoo to Jordan's JoFotara (Arabic: فوترتي, "My Invoice") national e-invoicing system, operated by the Income and Sales Tax Department (ISTD) under the Ministry of Finance. JoFotara is a direct-API, real-time Continuous Transaction Control (CTC) platform: your Odoo instance submits a Jordan-profile UBL 2.1 XML invoice directly to ISTD, which validates, clears, and returns a UUID and QR code synchronously. The QR is printed on the issued invoice PDF and constitutes the legal proof of clearance.
JoFotara is already mandatory for GST-registered taxpayers in Jordan — phased in since 2021 for large taxpayers, 2022 for medium, and ongoing rollout to all registered businesses. This is not a future mandate; Jordan Odoo users are currently out of compliance without it.
Compatibility: Odoo 17 / 18 / 19 (Community or Enterprise) Price: $299 (one-time) + $499 for the GCC E-Invoicing Core Engine License: Up to 3 domain activations Category: Accounting / Localizations / EDI
Jordan JoFotara is the newest and least-documented GCC e-invoicing regime. Validate the full document structure, authentication field names, response shape, and QR format against the ISTD sandbox (sandbox.jofotara.gov.jo) before any production go-live. The live-transmission path in this module is explicitly gated: production submission is refused unless the company environment mode is set to Production and credentials are configured.
Overview
How it works
Odoo invoice (account.move)
│
│ Jordan-profile UBL 2.1 XML (built by this module)
▼
ISTD JoFotara API ──── real-time clearance ────► UUID + QR code returned
│
(ISTD retains the invoice; UUID + QR stored on Odoo record; QR printed on PDF)
This architecture is distinct from:
- UAE / Peppol — no mandatory third-party ASP relay
- KSA ZATCA — no dual-phase HSM signing device, no cryptographic stamp before submission
What the module does
- OAuth2 client_credentials authentication — uses a
client_idandsecret_keyissued by the JoFotara portal after Jordan TIN registration; stored onres.companywith admin-only visibility, never printed or logged. - Jordan-profile UBL 2.1 document builder — 16% GST (Jordan calls it General Sales Tax, not VAT), JOD (Jordanian Dinar) at 3-decimal precision, B2B standard invoices with buyer TIN, B2C simplified invoices without buyer TIN, and credit notes with a billing reference to the original cleared UUID.
- Real-time clearance submission —
POST /api/invoice; ISTD validates in real time and returns a UUID and QR code string on success. - Submission state machine — draft / submitted / cleared / rejected / pending_retry; every state transition is tracked.
- Per-attempt audit log — each HTTP call to ISTD is recorded with HTTP status, message, and a response excerpt for traceability.
- Exponential-backoff retry queue — a scheduled cron retries 5xx server errors automatically (up to 5 attempts, backoff: 2^n minutes); the stored ISTD UUID is the at-most-once idempotency guard so a cleared invoice is never re-submitted.
- Status query —
GET /api/invoice/{uuid}lets you poll ISTD for the latest clearance status of a submitted invoice. - Sandbox / production environment switch — base URLs are configurable on
res.company; defaults point to the reported ISTD URLs. Production submissions are refused if the company environment is not explicitly set to Production.
Endpoints implemented
| Endpoint | Method | Purpose |
|---|---|---|
/api/get_token | POST | Obtain a Bearer token using client_id + secret_key |
/api/invoice | POST | Submit an invoice or credit note for real-time clearance |
/api/invoice/{uuid} | GET | Query clearance status by ISTD-assigned UUID |
Features intentionally not implemented (pending ISTD sandbox verification)
The following are stubbed and return a UserError with a clear explanation rather than fabricated behavior:
GET /api/taxpayer— endpoint path and response schema unverified- Seller-side XML digital signing (JoFotara Phase 2+) — signing algorithm and ISTD PKI CA are unknown; Phase 1 uses ISTD server-side clearance
- Local QR code generation — the JoFotara QR string is supplied by ISTD in the clearance response; the Jordan-specific content format is unverified and is never self-generated
Prerequisites
- Odoo 17, 18, or 19 (Community or Enterprise edition)
ecosire_einvoice_core— the ECOSIRE GCC E-Invoicing Core Engine must be installed first- An active ECOSIRE license for
ecosire_einvoice_jo - Python packages:
lxml,requests - A valid Jordan TIN (15-digit) registered with the ISTD
- JoFotara portal credentials (
client_idandsecret_key) — obtained from jofotara.gov.jo after TIN registration - Sandbox credentials for pre-production testing — registered separately at sandbox.jofotara.gov.jo; sandbox registration also requires a Jordan TIN
Installation
- Install the GCC E-Invoicing Core Engine first — this country pack depends on it.
- Download the Jordan JoFotara module ZIP from your ECOSIRE Dashboard.
- Extract it to your Odoo addons directory alongside the core engine:
unzip ecosire-einvoice-jo-*.zip -d /opt/odoo/addons/ - Install the required Python packages into the same environment that runs Odoo:
pip install lxml requests - Restart the Odoo service:
sudo systemctl restart odoo - In Odoo go to Apps, click Update Apps List.
- Search for ECOSIRE E-Invoicing | Jordan JoFotara and click Install.
- Activate your ECOSIRE license when prompted (see below).
After installation a JoFotara submenu appears under Accounting → JoFotara.
Configuration and Credentials
Step 1: Activate your ECOSIRE license
- Navigate to Settings → ECOSIRE License.
- Enter the license key you received from ECOSIRE.
- Click Activate. The module refuses to submit invoices until the license is active.
If activation returns an error, verify the key is for ecosire_einvoice_jo and that the domain matches your Odoo instance URL. Contact [email protected] if the problem persists.
Step 2: Obtain JoFotara API credentials
- Register or log in to the JoFotara portal at jofotara.gov.jo using your Jordan TIN.
- Navigate to the developer / API access section and apply for API credentials.
- ISTD issues a Client ID (
client_id) and a Secret Key (secret_key).
For sandbox testing, register separately at sandbox.jofotara.gov.jo. Sandbox credentials are issued independently and do not affect live fiscal records.
The JoFotara API uses secret_key (not the OAuth2 standard client_secret). This is consistent with ISTD integrator references. Confirm the exact field names against the official ISTD API documentation when you access the developer portal, and adjust the configuration accordingly.
Step 3: Configure company settings
- Go to Settings → Companies (or Settings → General Settings → Companies) and open your company record.
- Navigate to the JoFotara / E-Invoicing tab.
- Enter your credentials:
- JoFotara Client ID (
jo_jofotara_client_id) — from the ISTD portal - JoFotara Secret Key (
jo_jofotara_secret_key) — from the ISTD portal; stored with admin-only visibility, never displayed in logs
- JoFotara Client ID (
- Verify the base URLs (pre-filled with reported ISTD defaults):
- Sandbox Base URL —
https://sandbox.jofotara.gov.jo(verify against ISTD developer docs before use) - Production Base URL —
https://backend.jofotara.gov.jo(verify against ISTD developer docs before use)
- Sandbox Base URL —
- Set Company E-Invoice Environment to Sandbox during testing. Switch to Production only after successful sandbox verification.
Step 4: Configure GST tax mapping
Jordan uses General Sales Tax (GST) at a standard rate of 16%, not VAT. Ensure your Odoo tax configuration reflects this:
- Standard rate: 16% GST (tax category code
S) - Zero-rated: 0% (exports and certain exempted goods, category
Z) - Exempt: healthcare, education, and basic food items (category
E)
Map these to the appropriate Odoo tax records via Accounting → Configuration → Taxes. The UBL builder reads the tax category from the invoice line tax records.
Step 5: Configure JOD currency precision
JOD (Jordanian Dinar) uses 3 decimal places (fils). Verify that the JOD currency in Odoo is set to 3 decimal places under Settings → Technical → Currencies. The UBL builder enforces 3dp on all monetary amounts.
Usage
Submitting an invoice for clearance
- Create and confirm a customer invoice in Accounting → Customers → Invoices.
- The module automatically detects Jordan invoices (based on company country) and creates a JoFotara submission record in Draft state.
- Open the invoice and click Submit to JoFotara (or navigate to Accounting → JoFotara → Submissions and open the submission record).
- Click Submit Now.
- The module:
- Validates mandatory fields (seller TIN, invoice number, line items, GST amounts)
- Builds the Jordan-profile UBL 2.1 XML
- Authenticates with ISTD (
POST /api/get_token) - Submits the XML (
POST /api/invoice)
- On success, ISTD returns a UUID and QR code string. These are stored on the submission record and written back to the invoice. The state transitions to Cleared.
- The QR code is embedded in the invoice PDF. The invoice is legally valid only after clearance (UUID and QR issued by ISTD).
Submission states
| State | Meaning |
|---|---|
| Draft | Created, not yet submitted to ISTD |
| Submitted | Sent to ISTD, awaiting outcome |
| Cleared | ISTD cleared the invoice; UUID and QR code stored |
| Rejected | ISTD rejected the invoice (see the Attempts tab for error details) |
| Pending Retry | Transient failure (5xx); will be retried automatically by the cron |
Credit notes
Credit notes follow the same flow. The UBL builder automatically includes a BillingReference element pointing to the original invoice's ISTD UUID. The original invoice must be cleared (have a UUID) before you can clear a credit note referencing it.
Simplified invoices (B2C)
For B2C invoices, the module creates a Simplified submission (no buyer TIN required). The system determines the subtype from the partner type on the invoice. Individual / consumer partners trigger the simplified path.
Retry queue
If ISTD returns a 5xx server error, the submission moves to Pending Retry. A scheduled cron job checks pending submissions every few minutes and retries them with an exponential backoff (2, 4, 8, 16, 32 minutes). After 5 failed attempts the submission stays in Rejected for manual review. The stored UUID acts as the idempotency guard — a submission with an existing UUID is never re-submitted.
Manual status query
If a submission was sent but the response was unclear, open the submission record and click Query ISTD Status. The module calls GET /api/invoice/{uuid} and updates the state based on ISTD's response.
API Details
| Field | Value |
|---|---|
| Auth method | OAuth2 client_credentials (Bearer token) |
| Auth endpoint | POST /api/get_token at https://backend.jofotara.gov.jo (reported — verify) |
| Submit endpoint | POST /api/invoice |
| Status endpoint | GET /api/invoice/{uuid} |
| Sandbox base URL | https://sandbox.jofotara.gov.jo (reported — verify) |
| Production base URL | https://backend.jofotara.gov.jo (reported — verify) |
| Document format | UBL 2.1 XML, Jordan ISTD profile |
| Key config fields | jo_jofotara_client_id, jo_jofotara_secret_key, jo_jofotara_sandbox_base_url, jo_jofotara_prod_base_url |
The ISTD API base URLs above are widely cited in Jordan integrator references but could not be verified from primary sources at time of publication (jofotara.gov.jo requires in-country network access). Confirm the exact base URLs and endpoint paths against the official ISTD developer documentation before production go-live. Both the sandbox and production base URLs are configurable on the company record so you can correct them without a code change.
Troubleshooting
| Issue | Solution |
|---|---|
| License not active | Go to Settings → ECOSIRE License and verify the license key is entered and activated for ecosire_einvoice_jo |
| "Refusing production submission" error | Go to the company settings and confirm the Company E-Invoice Environment is set to Production; only change this after successful sandbox testing |
| Authentication failed (401) | Verify client_id and secret_key on the company record; confirm field names against ISTD developer documentation |
| Connection error / ECONNREFUSED | The ISTD API may be temporarily unavailable; check the base URLs on the company record against ISTD developer documentation |
| Submission rejected (400) | Open the submission's Attempts tab; the error message from ISTD (field-level validation failures) appears in the response excerpt; correct the invoice data and retry |
| Submission rejected (422) | Likely a business rule violation — duplicate invoice number or a credit note referencing an uncleared original; verify invoice number uniqueness and original UUID |
| QR code not printing on PDF | The QR string is stored on the submission record's ISTD QR Code field only after clearance; the PDF template reads it from the linked submission; verify the invoice is in Cleared state |
| Credit note missing billing reference | The original invoice must be cleared (have an ISTD UUID) before the credit note can reference it; clear the original first |
| "No ISTD UUID" on status query | The invoice has not been submitted yet; use Submit Now first |
| Cron not retrying pending submissions | Check Settings → Technical → Scheduled Actions and confirm the JoFotara Retry Pending Submissions cron is enabled and its interval is set |
| Base URL needs updating | ISTD may have changed the API endpoint; update the Sandbox Base URL or Production Base URL on the company record to match the current ISTD developer documentation |
FAQ
Does this module require the GCC E-Invoicing Core Engine?
Yes. ecosire_einvoice_jo is a country pack that depends on ecosire_einvoice_core. Install the core engine first.
Can I test without a real Jordan TIN? No. ISTD sandbox registration requires a valid Jordan TIN. You must have a Jordan TIN to obtain sandbox credentials.
Is seller-side XML digital signing required? For Phase 1 of JoFotara, ISTD performs server-side signing during the clearance response (returning the UUID and QR). Seller-side digital signing has been reported as a possible Phase 2+ requirement, but the algorithm and ISTD PKI specification are not confirmed. The module does not implement seller-side signing for Phase 1; if ISTD introduces this requirement, it will be added in a future version.
What happens if ISTD returns 5xx errors during peak periods? The submission moves to Pending Retry and the exponential-backoff cron retries it automatically. You can also click Retry Now on the submission record to force an immediate retry.
Can I submit invoices in foreign currencies? Jordan GST must be computed and reported in JOD even for foreign-currency invoices, using the exchange rate on the invoice date. Set the correct exchange rate in Odoo before confirming the invoice. The exact foreign-currency exchange rate field name in the JoFotara UBL profile requires confirmation from the ISTD XSD specification.
Is Point of Sale (POS) supported?
POS e-invoicing is not included in this release. The module covers account.move invoices, credit notes, and debit notes.
How long must e-invoices be archived?
Jordan GST law requires a 5-year archiving period (reported — verify the specific e-invoice archiving format and retrieval obligation from ISTD official circulars). Odoo stores all submission records and UBL XML on the jofotara.submission model indefinitely unless explicitly purged.
Support
- General Troubleshooting
- Email: [email protected]
- Support Portal
- GCC E-Invoicing Core Engine — required dependency
- GCC E-Invoicing | ZATCA Phase 2 — Saudi Arabia — KSA country pack