Malaysia MyInvois (LHDN) E-Invoicing
The ECOSIRE Malaysia MyInvois module connects Odoo's account.move (invoices, credit notes, debit notes) to the MyInvois Centralised CTC e-invoicing platform operated by LHDN / IRBM (Lembaga Hasil Dalam Negeri Malaysia -- Inland Revenue Board of Malaysia). Malaysia's e-invoicing model is a Direct Government REST API: your ERP builds a digitally-signed UBL 2.1 (MY) document and submits it straight to LHDN. LHDN validates, stamps a UUID + longId + QR URL, archives the document, and notifies the buyer. No mandatory ASP or clearance intermediary sits in the path.
Compatibility: Odoo 17 / 18 / 19 Price: $399 (one-time) License: LGPL-3
Malaysia phased its e-invoice mandate by annual turnover: Phase 1 (August 2024, turnover > MYR 100M), Phase 2 (January 2025, MYR 25M -- MYR 100M), Phase 3 (July 2025 onwards, all remaining taxpayers). Verify current enforcement status and any grace periods against the latest LHDN circulars at hasil.gov.my.
Key Features
- OAuth 2.0 Client Credentials authentication (taxpayer and intermediary on-behalf-of modes)
- UBL 2.1 (MY) document builder: Invoice, Credit Note, Debit Note, Refund Note (types 01--04)
- Self-billed invoice types 11--14 (foreign vendor payments, agent disbursements, imports)
- Batch document submission -- up to 100 documents per API call
- Async status polling via
ir.cron(polls submission UID until cleared or rejected) - Cancel action (issuer, 72-hour window from LHDN validation)
- Reject action (buyer, 72-hour window from invoice issuance)
- Consolidated B2C monthly invoice (General Public TIN
EI00000000010) - TIN / BRN / NRIC / Passport validation against LHDN registry
- MSIC code and SST registration fields on company record
- LHDN QR URL renderer -- renders the stamped URL returned by LHDN, never self-generated
- Submission state machine with full per-call audit log
- Notification poller that surfaces buyer rejections into the invoice chatter
- Config-driven API hosts (sandbox preprod vs production) -- no hardcoded URLs or secrets
Prerequisites
- Odoo 17, 18, or 19 (Community or Enterprise edition)
ecosire_einvoice_core(the ECOSIRE e-invoicing engine -- installed automatically as a dependency)- An active ECOSIRE license for
ecosire_einvoice_my - A registered taxpayer TIN issued by LHDN
- MyInvois Portal access to register your ERP system and obtain sandbox/production credentials
- A digital certificate from an LHDN-accepted Certificate Authority (required for document signing -- see the Digital Signing note below)
Installation
- Download the module ZIP from your ECOSIRE Dashboard
- Extract to your Odoo addons directory:
unzip ecosire-einvoice-my-*.zip -d /opt/odoo/addons/ - Restart the Odoo service:
sudo systemctl restart odoo - Navigate to Apps, click Update Apps List
- Search for "ECOSIRE E-Invoicing | Malaysia MyInvois" and click Install
- Activate your ECOSIRE license when prompted (see Configuration below)
Configuration
Step 1: Activate your ECOSIRE License
- Navigate to Settings > ECOSIRE License
- Enter the license key provided after purchase
- Click Activate -- the module will verify the key against the ECOSIRE licensing server
Step 2: Register your ERP System in the MyInvois Portal
Before configuring Odoo, you must obtain API credentials from LHDN:
- Log in to the MyInvois Portal (preprod:
preprod.myinvois.hasil.gov.my; production:myinvois.hasil.gov.my) - Navigate to the ERP System Registration section
- Register your Odoo instance to receive a Client ID and Client Secret
- For intermediary mode: grant the intermediary's Client ID the required API permissions in the portal and note the taxpayer TIN (and ROB number if applicable) for the
on-behalf-ofheader
Begin with the LHDN preprod (sandbox) environment. Sandbox credentials are separate from production. Obtain sandbox credentials from the LHDN portal sandbox registration process and verify the full submission flow before switching to production mode.
Step 3: Configure Company Identity (LHDN Mandatory Fields)
- Navigate to Settings > Companies > your company
- Open the MyInvois tab and fill in:
- MyInvois TIN (
myinvois_tin) -- LHDN-issued Tax Identification Number (11--14 alphanumeric characters) - Business Registration No. (BRN) (
myinvois_brn) -- SSM-issued Business Registration Number - SST Registration No. (
myinvois_sst_id) -- Sales & Service Tax number; enterNAif not SST-registered - MSIC Code (
myinvois_msic_code) -- Malaysia Standard Industrial Classification (5-digit code) - Business Activity Description (
myinvois_activity_desc) -- free-text description of your main business activity
- MyInvois TIN (
Step 4: Configure the MyInvois Connection
- Navigate to Accounting > MyInvois > Configuration
- Set Environment to
Sandbox (preprod)while testing, thenProductionfor live submission - The API and token base URLs are pre-filled with the LHDN defaults -- adjust only if LHDN changes its hostnames
- Enter your Client ID (
client_id) and Client Secret (client_secret) from the portal - Leave Scope as
InvoicingAPI(the LHDN default) - For intermediary mode: tick Intermediary Mode and enter the taxpayer TIN (or TIN:ROB) in the On-Behalf-Of field
- Click Test Connection -- this exercises the CONFIRMED OAuth 2.0 token endpoint (
POST /connect/token) and displaysOK (token acquired)on success
Step 5: Verify Sandbox and Enable Live Transmission
The module gates all document endpoints behind a Sandbox Verified flag. These endpoints are implemented from LHDN published documentation and must be confirmed against the LHDN preprod sandbox before enabling production submissions:
- Submit test documents in the preprod environment using the Submit to MyInvois action on a test invoice
- Confirm the full cycle: submission accepted, UUID returned, status polled to
Valid - Once the sandbox handshake succeeds, tick Sandbox Verified in the configuration record
- Switch Environment to
Productiononly after the sandbox cycle completes cleanly
Document signing (XAdES-ENVELOPED over UBL 2.1 XML) is required by LHDN. This module provides the signing infrastructure but raises a clear error until you supply a valid taxpayer digital certificate from an LHDN-accepted Certificate Authority (MSC Trustgate, Telekom Malaysia / DigiCert, MIMOS). Obtain the certificate through the MyInvois Portal and configure it under Accounting > MyInvois > Configuration before live submission. The exact canonicalization form and certificate authority list should be verified against the current LHDN SDK at sdk.myinvois.hasil.gov.my.
Usage
Submitting an Invoice
- Confirm an invoice (
account.move) in Odoo as you normally would - Open the validated invoice and click Submit to MyInvois
- The module builds the UBL 2.1 (MY) XML, computes the SHA-256 hash, Base64-encodes it, and POSTs to
/api/v1.0/documentsubmissions - A
myinvois.submissionrecord is created with stateSubmittedand the LHDNsubmissionUid - The
ir.cronpoller checks the submission status (viaGET /api/v1.0/documentsubmissions/{submissionUid}) until LHDN returnsValid,Invalid, orPartially Valid - On success the invoice record is updated with the LHDN Document UUID, Long ID, and QR URL
Batch Submission
For high-volume scenarios, multiple confirmed invoices can be batched:
- From the invoice list, select the invoices to submit
- Use Action > Submit to MyInvois (Batch)
- Up to 100 documents are sent per API call; larger selections are automatically split into batches
- Monitor progress in Accounting > MyInvois > Submissions
Consolidated B2C Invoice
For B2C transactions below the LHDN threshold (currently reported as MYR 500 per transaction -- verify the current threshold in LHDN circulars):
- Navigate to Accounting > MyInvois > Consolidated Invoice
- Select the month and the B2C invoices to consolidate
- The module generates a single Invoice (type 01) addressed to the General Public TIN
EI00000000010 - Submit by the 7th day of the following month (LHDN reported deadline)
Cancelling a Document
After LHDN validates a document, the issuer has a 72-hour window to cancel it:
- Open the
myinvois.submissionrecord for the document - Click Cancel and enter a cancellation reason
- The module sends
PUT /api/v1.0/documents/state/{uuid}/statewithstatus: cancelled - Cancellation is blocked if the buyer has already accepted or rejected the document
Checking Buyer Rejections
The notification poller (ir.cron) periodically calls GET /api/v1.0/notifications/taxpayer to fetch LHDN system notifications. Buyer rejections are surfaced as chatter messages on the linked invoice, with the rejection reason and timestamp.
Validating a Partner's TIN
Before issuing a B2B invoice, validate the buyer's identity:
- Open the partner record and navigate to the MyInvois tab
- Click Validate TIN -- the module calls
GET /api/v1.0/taxpayer/validate/{idType}/{idValue} - A green indicator confirms the TIN is registered in the LHDN registry
- An invalid TIN will cause LHDN to reject the entire submission batch; validate before submitting
API Details
| Field | Value |
|---|---|
| Auth method | OAuth 2.0 Client Credentials Grant |
| Token endpoint (sandbox) | https://preprod-api.myinvois.hasil.gov.my/connect/token |
| Token endpoint (production) | https://api.myinvois.hasil.gov.my/connect/token |
| Document submission | POST /api/v1.0/documentsubmissions |
| Status polling | GET /api/v1.0/documentsubmissions/{submissionUid} |
| Document details | GET /api/v1.0/documents/{uuid}/details |
| Cancel / Reject | PUT /api/v1.0/documents/state/{uuid}/state |
| Notifications | GET /api/v1.0/notifications/taxpayer |
| TIN validation | GET /api/v1.0/taxpayer/validate/{idType}/{idValue} |
| Batch limit | 100 documents per submission call |
| Token lifetime | 3,600 seconds (auto-refreshed) |
| Key config fields | client_id, client_secret, myinvois_tin, myinvois_brn, myinvois_sst_id, myinvois_msic_code |
Troubleshooting
| Issue | Solution |
|---|---|
| License not active | Go to Settings > ECOSIRE License and verify the key is activated |
| Connection test fails | Check Client ID and Client Secret match those in the MyInvois Portal; confirm you are pointing at the correct environment (sandbox vs production) |
| "Sandbox Verified flag not set" error | Complete a successful sandbox submission cycle first, then tick Sandbox Verified in the configuration record |
| Document signing error | Ensure a valid digital certificate from an LHDN-accepted CA is configured; verify against sdk.myinvois.hasil.gov.my signing requirements |
| TIN validation returns 400 | The buyer TIN is not registered in the LHDN registry or the format is wrong (11--14 alphanumeric); contact the buyer to provide their correct LHDN TIN |
| Submission returns partial acceptance | Some documents in the batch passed and others failed; review the rejectedDocuments entries in the submission record's audit log for per-document error codes |
| Status stuck at "In Progress" | LHDN async validation can take several minutes for large batches; the cron poller retries automatically -- check the submission audit log for the latest poll result |
| Cancel rejected with 422 | The 72-hour cancellation window has closed or the buyer has already accepted the document; issue a Credit Note instead |
| QR URL empty on invoice | The document has not yet reached Valid state; the QR URL is only returned after LHDN stamps the document |
| No MyInvois configuration found for company | Create a configuration record under Accounting > MyInvois > Configuration for the active company |