DEV Community

Samir Chatwiti
Samir Chatwiti

Posted on

Why MyInvois rejects your e-invoice — and how to catch it before LHDN does

Malaysia's MyInvois mandate is now real for most businesses — Phase 4 pulled companies with RM1-5M turnover into the system in January 2026. If you build or integrate the software that emits those e-invoices (an ERP, a POS, a SaaS billing module), you have discovered the painful part: LHDN rejects documents, and it rejects them after you submit them.

This post walks through the most common rejection causes I've seen, and a way to catch all of them in CI before anything reaches LHDN.

The usual suspects
A MyInvois document (UBL 2.1, XML or JSON) fails for a handful of recurring reasons:

Structure — the document doesn't validate against the official OASIS UBL 2.1 XSD: wrong element order, missing wrappers, bad namespaces.
Missing mandatory fields — invoice type code, issue date/time, currency, supplier or buyer TIN, MSIC code, line items, TaxTotal, LegalMonetaryTotal.
Code-list violations — a currency that isn't ISO-4217, an MSIC code that doesn't exist, a state code or unit code outside the LHDN tables.
Totals that don't add up — TaxInclusiveAmount ≠ TaxExclusiveAmount + tax, line extensions that don't sum.
A broken XAdES signature — the enveloped signature's document digest doesn't match (the document was touched after signing), the SignedProperties digest is wrong, or the signing certificate is expired / lacks the Document Signing EKU.
The first four are boring but frequent. The fifth is the sneaky one: serialize your XML differently after signing — pretty-print it, re-encode it, let a middleware "fix" a namespace — and the digest no longer matches.

Pre-flight, not post-mortem
The pattern that works: validate every document at the moment it's generated, not when LHDN bounces it. Keyless validation (no certificate, no MyInvois account, no token) means you can run it anywhere — CI pipelines, a pre-submit hook, a partner-onboarding gate.

Here's the whole check as one HTTP call, using the Malaysia MyInvois E-Invoice Validator (free tier available):

curl --request POST \
--url https://malaysia-myinvois-e-invoice-validator.p.rapidapi.com/validate \
--header 'Content-Type: application/xml' \
--header 'x-rapidapi-host: malaysia-myinvois-e-invoice-validator.p.rapidapi.com' \
--header 'x-rapidapi-key: YOUR_RAPIDAPI_KEY' \
--data-binary @invoice.xml
You always get HTTP 200 with a JSON verdict. Here is a real response for an invoice with a missing supplier TIN and a bogus currency:

{
"valid": false,
"documentType": "01",
"errorCount": 3,
"warningCount": 5,
"findings": [
{ "level": "error", "ruleId": "MY-CORE-SUPPLIER-TIN",
"text": "Supplier TIN (PartyIdentification schemeID='TIN') is missing.",
"location": "cac:AccountingSupplierParty" },
{ "level": "error", "ruleId": "MY-CODE-CURRENCY",
"text": "DocumentCurrencyCode 'XYZ' is not an ISO-4217 code.",
"location": "cbc:DocumentCurrencyCode" }
]
}
Every finding has a stable ruleId (MY-STRUCT-, MY-CORE-, MY-CODE-, MY-MATH-, MY-SIG-*), so you can assert on specific rules in tests, or map them to user-facing messages in your product.

The signature layer goes deep for a keyless check: document digest recomputation (with the exact canonicalization MyInvois expects), SignedProperties digest, RSA-SHA256 SignatureValue against the embedded X.509, certificate validity window, Document Signing EKU, and the XAdES SigningCertificate binding.

What a pre-flight can't do
Honesty matters in compliance tooling. A keyless validator cannot: verify the trust chain to the LHDNM / Pos Digicert CA, confirm a TIN actually exists, or perform the submission itself (the unique ID and QR come back from LHDN). valid: true means "structurally ready to submit", not "accepted".

Wrap-up
Validate at generation time, not at submission time.
Assert on ruleIds in CI so regressions in your invoice generator are caught by the build.
Treat the XAdES signature as part of your test surface — most "mystery" rejections are digest mismatches introduced after signing.
I maintain validators like this for five mandated e-invoicing regimes (Malaysia, Dominican Republic, Nigeria, Bolivia, Costa Rica) — overview with links here: github.com/SamirChatwiti/e-invoice-validators.

Top comments (0)