Malaysia MyInvois (LHDN) E-Invoicing
| Technical name | ecosire_einvoice_my |
| Odoo versions | 17.0, 18.0, 19.0 (Community or Enterprise) |
| Current shipped version | 19.0 -> 19.0.1.1.3, 18.0 -> 18.0.1.1.4, 17.0 -> 17.0.1.1.4 |
| Price | $599 USD, one-time (requires ecosire_einvoice_core) |
| Odoo module licence | OPL-1 |
| Category | Accounting / Localizations / EDI |
This is the Malaysia country pack for the ECOSIRE e-invoicing core engine. It connects Odoo invoices and credit notes to MyInvois, the e-invoicing system operated by LHDN / IRBM (Lembaga Hasil Dalam Negeri Malaysia, the Inland Revenue Board of Malaysia).
Malaysia uses a direct government REST API: your ERP builds a digitally signed UBL 2.1 (MY) document and submits it straight to LHDN. LHDN validates it, stamps a UUID and a long ID, and notifies the buyer. There is no mandatory service provider in between.
The package is fully functional on installation: there is no separate licence module to install, no key to enter and no activation step. Use is governed by the OPL-1 licence terms.
LHDN only accepts digitally signed documents (XAdES over the UBL 2.1 XML). This release does not sign documents yet. The exact signature form, canonicalization and accepted Certificate Authorities are still to be confirmed against the LHDN MyInvois SDK and your own taxpayer certificate, and signing against an unconfirmed scheme would make every submission fail.
What works today: the connection to LHDN (OAuth 2.0 token), company and partner identity fields, the UBL 2.1 (MY) document builder with its SHA-256 hash, and the submission records, audit log and scheduled actions. When you press Submit to LHDN (or the invoice's MyInvois button), the module builds the document and then stops with a clear message that signing is not yet enabled. Nothing is sent to LHDN and the submission is left unchanged. Plan your go-live date with this in mind.
Malaysia phased its e-invoice mandate by annual turnover: Phase 1 (August 2024, turnover above MYR 100M), Phase 2 (January 2025, MYR 25M to MYR 100M), Phase 3 (July 2025 onwards, the remaining taxpayers). Check current enforcement dates and any grace periods in the latest LHDN guidance at hasil.gov.my.
What it does
- OAuth 2.0 client-credentials connection to LHDN, for a taxpayer or for an intermediary acting on behalf of a taxpayer (
onbehalfofTIN or TIN:ROB). - Sandbox and production environments with every API host held in configuration. Nothing is hardcoded.
- UBL 2.1 (MY) document builder for invoice, credit note, debit note and refund note types (01 to 04) and the self-billed types (11 to 14). An invoice is sent as type 01, a customer credit note as 02 and a vendor refund as self-billed 12.
- Pre-build checks: the supplier TIN, BRN and MSIC code must be set on the company and the invoice must carry a currency, or the document is not built.
- General Public TIN (
EI00000000010) used automatically when the buyer has no TIN (B2C). - Submission records with a state machine: Draft, Submitted, Cleared (Valid), Rejected/Invalid, Cancelled, Pending Retry.
- Status polling every 15 minutes and an automatic retry every hour for submissions waiting to be retried (up to 5 attempts).
- Cancel (issuer) and Reject (Buyer) actions on a submitted or cleared document.
- LHDN validation link: once a document is valid, the module builds the MyInvois portal URL from the LHDN-stamped UUID and long ID. It never generates its own QR data.
- Buyer TIN check against the LHDN taxpayer registry from the partner form.
- Per-call audit log of every build, submit, poll, cancel and reject, and multi-company record rules on configuration and submissions.
Only the endpoints in the published MyInvois contract are implemented. The token endpoint is confirmed against the LHDN SDK; every document endpoint is taken from LHDN's published documentation and stays locked until you confirm it in the sandbox (see Sandbox Verified below).
Requirements
| Requirement | Detail |
|---|---|
| Odoo | 17.0, 18.0 or 19.0 (Community or Enterprise) |
| Core engine | ecosire_einvoice_core installed (see the core engine page) |
| Python packages | lxml, requests |
| Licence | None required: no activation key, no separate licence module |
| LHDN access | A taxpayer TIN and MyInvois Portal access to register your ERP system and obtain a Client ID and Client Secret |
| Signing certificate | A taxpayer digital certificate from an LHDN-accepted Certificate Authority, needed once document signing is enabled |
Installation
- Install the core engine first.
- Download this pack from the Odoo Apps Store after purchase and extract it into your addons directory:
unzip ecosire_einvoice_my-*.zip -d /opt/odoo/addons/sudo systemctl restart odoo
- In Odoo go to Apps and click Update Apps List.
- Search for ECOSIRE E-Invoicing | Malaysia MyInvois (LHDN) and click Install.
After installation a MyInvois menu appears under Accounting, with Submissions and Configuration.
Menu map
| Menu | What it is for |
|---|---|
| Accounting > MyInvois > Submissions | Every document submission, its LHDN identifiers, state and audit log |
| Accounting > MyInvois > Configuration | One connection record per company: environment, API hosts, credentials, intermediary mode, Sandbox Verified |
| Company form, MyInvois (Malaysia LHDN) section | Supplier identity sent on every document |
| Partner form, MyInvois tab | Buyer TIN, BRN, secondary ID and the Validate with LHDN button |
| Invoice form, MyInvois smart button | Creates (or reuses) the submission and submits it |
Configuration
Step 1: Register your ERP system in the MyInvois Portal
- Log in to the MyInvois Portal (preprod:
preprod.myinvois.hasil.gov.my; production:myinvois.hasil.gov.my). - Open the ERP System Registration section and 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 it applies).
Sandbox and production credentials are separate. Start in the preprod sandbox.
Step 2: Company identity
Open Settings > Companies, select your company and fill in the MyInvois (Malaysia LHDN) section:
- MyInvois TIN (
myinvois_tin): your LHDN-issued Tax Identification Number - Business Registration No. (BRN) (
myinvois_brn): your SSM business registration number - SST Registration No. (
myinvois_sst_id): your Sales and Service Tax number, orNAif you are not SST-registered - MSIC Code (
myinvois_msic_code): your 5-digit Malaysia Standard Industrial Classification code - Business Activity Description (
myinvois_activity_desc): a short description of your main business activity
TIN, BRN and MSIC code are mandatory: a document is not built without them.
Step 3: The MyInvois connection
- Go to Accounting > MyInvois > Configuration and create the record for your company (one per company).
- Set Environment to
Sandbox (preprod)while testing. - The sandbox and production API and token hosts are pre-filled with the LHDN defaults (
https://preprod-api.myinvois.hasil.gov.myandhttps://api.myinvois.hasil.gov.my). Change them only if LHDN changes its hostnames. - Enter the Client ID and Client Secret from the portal. Both are visible to system administrators only, the secret is a password field, and neither is written to the logs.
- Leave Scope as
InvoicingAPI. - For intermediary mode, tick Intermediary Mode and enter the taxpayer TIN (or TIN:ROB) in On-Behalf-Of.
- Click Test Connection. It requests a token from
POST /connect/tokenwithout sending any document, and showsOK (token acquired)in Last Connection Test on success.
Step 4: Sandbox Verified
Every document endpoint (submit, status, cancel/reject, TIN validation and the others) is locked behind the Sandbox Verified flag. Until it is ticked, these calls stop with a message explaining that the endpoint is not yet confirmed against the LHDN sandbox, so nothing can be sent to an unconfirmed URL.
Tick Sandbox Verified only after you have confirmed the document endpoints against the LHDN preprod sandbox, and switch Environment to Production only after that.
Daily usage
Partner TIN check
- Open the buyer's partner record and go to the MyInvois tab.
- Enter the buyer's MyInvois TIN and a secondary identifier: MyInvois ID Type (NRIC, Passport, BRN or Army) and MyInvois ID Value. If no ID value is set, the BRN is used.
- Click Validate with LHDN. The module calls
GET /api/v1.0/taxpayer/validate/{tin}with the ID type and value, and ticks TIN Validated when LHDN confirms the match.
A buyer without a TIN is invoiced with the General Public TIN EI00000000010.
Building and submitting a document
- Confirm a customer invoice or credit note (or a vendor refund) as usual.
- Click the MyInvois smart button on the invoice. The module creates a submission record linked to the invoice, builds the UBL 2.1 (MY) XML and its SHA-256 hash, then submits it.
- You can also work from Accounting > MyInvois > Submissions: Build Document builds the XML and hash locally without sending anything, and Submit to LHDN sends it.
In this release the submit step stops at signing (see the note at the top of this page): Odoo shows the signing message and nothing is sent. To review the XML before go-live, create the submission from Submissions and use Build Document. Once signing is enabled, an accepted document moves to Submitted with its LHDN Submission UID and Document UUID, and a submission whose call fails moves to Pending Retry.
Status, cancel and reject
- Poll Status (or the 15-minute scheduled action) reads
GET /api/v1.0/documentsubmissions/{submissionUid}and moves the submission to Cleared (Valid), Rejected/Invalid or Cancelled. A valid document receives its Long ID and the LHDN validation URL. - Cancel sends the issuer's cancellation to
PUT /api/v1.0/documents/state/{uuid}/state. LHDN allows cancellation within 72 hours of validation. - Reject (Buyer) sends a buyer rejection to the same endpoint, within LHDN's 72-hour window.
- Submissions in Pending Retry are retried every hour, up to 5 attempts.
Audit log
Every submission keeps its own audit log (build, submit, poll, cancel, reject, validate) with the result and message of each call. Use it first when you need to know what was sent and what LHDN answered.
API details
| Field | Value |
|---|---|
| Auth method | OAuth 2.0 client credentials (confirmed) |
| 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 (at most 100 documents per call) |
| Submission status | GET /api/v1.0/documentsubmissions/{submissionUid} |
| Document details / raw | GET /api/v1.0/documents/{uuid}/details, GET /api/v1.0/documents/{uuid}/raw |
| Cancel / reject | PUT /api/v1.0/documents/state/{uuid}/state |
| TIN validation | GET /api/v1.0/taxpayer/validate/{tin}?idType=...&idValue=... |
| Recent documents, notifications, document types | /api/v1.0/documents/recent, /api/v1.0/notifications/taxpayer, /api/v1.0/documenttypes |
| Endpoint status | Token endpoint confirmed; all others locked until Sandbox Verified |
Troubleshooting
| Issue | Solution |
|---|---|
| "MyInvois XAdES digital signing is not yet enabled" | Expected in this release: document signing is not yet available, so nothing is sent. See the note at the top of this page |
| "...uses an endpoint that is REPORTED..." | Tick Sandbox Verified on the configuration once you have confirmed the endpoints against the LHDN sandbox |
| Test Connection fails | Check the Client ID and Client Secret against the MyInvois Portal and that Environment points at the matching sandbox or production host |
| "Cannot build MyInvois document" | Fill in the company TIN, BRN and MSIC code, and make sure the invoice has a currency |
| "No MyInvois configuration found for company" | Create the configuration under Accounting > MyInvois > Configuration for the active company |
| Validate with LHDN asks for an ID value | Enter a MyInvois ID Value (or the BRN) on the partner, with its MyInvois ID Type |
| Validation URL empty on a submission | It is set only after LHDN marks the document Valid and returns its long ID |
Release notes
1.1.3 (Odoo 19) and 1.1.4 (Odoo 18 and 17): installs on its own
The package no longer asks for a separate ECOSIRE licence module. Earlier downloads could not be installed on a fresh Odoo because they depended on a module that was never part of the package. All references to it have been removed from the module and its tests, there is no activation step, and a test now checks on every build that the package is self-contained.
Upgrade to 19.0.1.1.3, 18.0.1.1.4 or 17.0.1.1.4. No configuration changes are needed and your submissions and audit log are untouched.
Earlier
- 1.1.2: one failing record in a scheduled poll or retry no longer stops the rest of the run.
- 18.0 / 17.0 1.1.3: the App Store price was aligned with ecosire.com at $599 USD.