The MyInvois API is the connection between a business system and LHDN's e-invoicing platform. Instead of a person filling in a form, your software builds an e-invoice, signs it, sends it to LHDN and reads back the validation result — all without anyone opening a browser.
It is worth being clear about what it is not. The API is a transmission mechanism, not a product. It does not keep your books, store your customers or replace your invoicing software. It is the doorway those systems use to reach MyInvois. This page explains what passing through that doorway actually involves: what you need before you can call anything, what a document has to look like, how submission behaves, what the limits are, and whether building it yourself is the right call.
What the MyInvois API is
LHDN documents two groups of endpoints, and the split tells you how the system is organised.
The Platform API handles everything that is not an invoice: logging in, asking which document types and versions the system currently accepts, and reading your notification history. The e-Invoicing API handles documents themselves — validating a TIN, submitting, cancelling, rejecting, and retrieving what you sent or received.
Both are described in the MyInvois SDK, currently SDK 1.0, whose release notes were last updated on 25 September 2026. Some of its changes are scheduled rather than live: the notes of 6 August and 25 September 2026 schedule production changes for 24 October 2026. The SDK changes, so treat any endpoint list — including the ones on this page — as a snapshot rather than a contract.
Who actually needs it
Not everyone connecting to MyInvois needs to build anything. There are really three positions:
- You do not need the API at all. Low volume, and the MyInvois Portal handles it. The portal is free, needs no digital certificate of your own, and includes a batch upload for more than one invoice at a time.
- You need API submission, but not your own integration. This is most businesses. Your accounting or ERP software already connects, or a service provider connects for you. You never see an endpoint.
- You need to build it. Usually because invoice volume is high, because invoices originate in a system nobody sells a connector for, or because the data that becomes an invoice lives somewhere that would be painful to export.
The middle position is a common one: the question "do we need the MyInvois API?" is often really "does our software support it?" Those have very different answers.
How the API differs from the portal
| MyInvois Portal | API | |
|---|---|---|
| Who does the work | A person, on a form or a spreadsheet upload | Your system, automatically |
| Digital certificate | Not needed — the portal signs on your behalf | Signing requirements depend on the document version; you or an authorised provider may hold the certificate |
| Volume | Suitable for lower-volume/manual submission | Better suited to system-generated and higher-volume submission |
| Validation result | Shown on screen | Returned asynchronously, read back by your system |
| Setup effort | User and taxpayer-profile setup | Requires a development/integration project |
| What breaks | A person makes a mistake | Credentials expire, schemas change, jobs fail silently |
The last row matters more than it looks. An automated integration fails quietly; a person notices when a form rejects them. Any serious integration needs someone watching it.
The three ways to connect
LHDN's e-Invoice Guideline describes API transmission as happening by one of three routes.
| Route | What it means | Who holds the build |
|---|---|---|
| Direct ERP integration | Your own system talks to MyInvois using your taxpayer credentials | You |
| Through a Peppol technology provider | An accredited Peppol access point transmits on your behalf, using the Peppol network for exchange with trading partners | The provider |
| Through a non-Peppol technology provider | A software vendor or service provider transmits on your behalf without using Peppol | The provider |
Peppol is worth one clarification, because it gets confused with validation. Peppol is an international network for exchanging structured documents between trading partners. It does not perform LHDN's tax validation — that still happens in MyInvois. A Peppol provider can do both jobs in one workflow, but they remain two different things.
Where the intermediary fits
Separately from those routes, a taxpayer can appoint an intermediary: a company authorised to act on their behalf inside MyInvois. This is an authorisation model, not a technology one, and it changes who authenticates.
A few things about intermediaries are set by LHDN rather than by your software:
- Registration as an intermediary is restricted to businesses, companies or organisations. An individual taxpayer cannot register in their own name.
- The taxpayer grants permissions, and those permissions apply to the intermediary's profile.
- An intermediary profile cannot be deleted once registered. To end the arrangement you set the "Representation To" date, which deactivates further action while preserving the historical records.
That last point is the one to plan around: an appointment that lapses does not produce an error message in your own system. Submissions simply stop being authorised.
What you need before you can call anything
Client credentials
An ERP system that submits using your own identity has to be registered in your taxpayer profile in the MyInvois Portal, under Representatives. LHDN issues a Client ID and Client Secret for it, and there is no restriction on how many systems you register. You can regenerate the credentials from the same place if they are ever exposed.
Treat them as you would a banking credential. Anyone holding them can submit e-invoices in your name.
Authentication itself is the OAuth 2.0 client credentials flow — a POST to /connect/token on LHDN's identity service, conceptually:
POST /connect/token
grant_type = client_credentials
client_id = <your client id>
client_secret = <your client secret>
scope = InvoicingAPI
The response carries an access_token, a token_type of Bearer, and an expires_in. Tokens are valid for 60 minutes. LHDN explicitly names requesting a fresh token for every call as an anti-pattern — cache the token for its stated lifetime and reuse it.
An intermediary authenticates the same way, with one addition: an onbehalfof header carrying the TIN of the taxpayer being represented. The same integration therefore serves many clients by varying one header rather than by holding many sets of credentials.
The digital certificate
This is the requirement that most often stalls an integration, because it is procurement rather than code.
For ordinary API submissions, v1.1 includes digital-signature validation and is strongly recommended. The SDK currently permits v1.0 without signature validation until LHDN announces its retirement. SVDP disclosures use their designated versions. Where digital signing is required, the signing certificate must meet LHDN's X.509 certificate requirements. The certificate must come from a Malaysian certification authority — the recognised authorities are listed on the MCMC website — and must be issued at organisation level, not to an individual. Its subject has to carry the organisation name, country, the TIN (as the organisation identifier) and the organisation's business registration number (BRN, as the serial number) linked to that TIN, and it needs Non-Repudiation key usage and the Document Signing extended key usage.
Two practical notes from LHDN's SDK FAQ: both locally installed ("soft") and server-based ("roaming") certificates are acceptable, and an authorised service provider may sign with its own certificate for its customers rather than obtaining one per customer. A group of companies can either procure certificates independently or appoint one subsidiary as the intermediary for the rest.
Start this early. It is the one item on the list that cannot be shortened by working harder.
What a document has to look like
UBL 2.1, as XML or JSON
MyInvois accepts structured documents following the UBL 2.1 schema, in either XML or JSON. The format is declared as part of the submission. A PDF is not an e-invoice as far as MyInvois is concerned — the PDF a buyer eventually sees is produced from the validated document, not submitted as one.
Each document carries a type code — invoices, credit notes, debit notes and refund notes, plus their self-billed equivalents — and each type has versions with their own lifecycle and active date ranges. Your integration should read the current document type versions from the Platform API rather than hard-coding a version that may later be deactivated.
What actually goes in the fields is a separate subject; the 55 mandatory fields covers that, and self-billed e-invoices and consolidated e-invoices cover the two document patterns that behave differently from an ordinary invoice.
The hash and the signature
Each submitted XML or JSON document has a documentHash calculated using SHA-256. This submission hash is separate from the digital signature.
For signed versions, follow the SDK signature creation procedure exactly. It defines the transformed document digest, signature value, certificate digest and signed-properties digest used in the signature structure. This summary is not an implementation algorithm.
This is the part most worth using a library for. Getting canonicalisation subtly wrong produces a document that looks correct and fails validation.
The submission workflow
- Step 1
Authenticate
Exchange Client ID and Secret for an access token. Cache it — it lasts 60 minutes. - Step 2
Build
Construct the UBL 2.1 document in XML or JSON, against the current document type version. - Step 3
Sign and hash
Follow the SDK signing procedure where required by the document version, and provide the SHA-256 documentHash for submission. - Step 4
Submit
POST the batch. HTTP 202 returns a submission UID, UUIDs for accepted documents and details of any immediately rejected documents. - Step 5
Poll
Check the submission status every few seconds until it settles. - Step 6
Reconcile
Store the UUID and status against your own invoice record. This is yours to keep.
Why you get a 202 and not a verdict
Submission is asynchronous, and this catches out anyone expecting a normal request-response API.
MyInvois runs a minimal set of checks synchronously and then returns HTTP 202 Accepted. The response carries a submissionUID, an acceptedDocuments list pairing each document's assigned UUID with your own reference number, and a rejectedDocuments list for anything refused outright. A 202 means "received for processing" — it does not mean the invoice is valid.
Full validation happens afterwards. Your system finds out by calling Get Submission with the submission UID. LHDN's guidance is to wait a period appropriate to the size of the batch, then poll at a 3–5 second interval.
Submission status resolves to in progress, valid, partially valid or invalid. Individual documents resolve to Submitted, Valid, Invalid or Cancelled. Partially valid is the case worth designing for deliberately: some documents in your batch passed and some did not, and your system has to handle both in one response.
The current SDK does not document a webhook callback mechanism. Notifications are retrieved through the Platform API instead, but the working pattern for submission status is submit, then poll.
Reading back what you submitted
Several endpoints return documents, and LHDN is unusually direct about which one to use for which job. Using the wrong one is a common cause of throttling.
| Endpoint | Use it for | Not for |
|---|---|---|
| Get Submission | Checking whether a submission has finished processing | — |
| Get Document Details | Retrieving validation errors on a document that came back invalid | Routine status checking |
| Get Document | Retrieving the document source and its tax authority metadata | — |
| Get Recent Documents | Troubleshooting, within the last 31 days | Reconciliation against your own records |
| Search Documents | Auditing and investigation, with filters | Reconciliation against your own records |
| Validate Taxpayer's TIN | Checking a buyer's TIN when you set the buyer up | Calling before every submission |
The recurring theme is that MyInvois is not your system of record. Search windows are capped at 31 days between start and end dates, a search returns at most 10,000 documents, and LHDN states plainly that these endpoints were not designed for reconciling an ERP against MyInvois. Your own database holds the mapping from your invoice to its UUID, status and validation time. Build that in from the start rather than planning to query it back later.
The TIN row is worth acting on too: validate a buyer's TIN when you create or edit the buyer record and cache the outcome, rather than calling it on every invoice. An incorrect TIN can cause validation to fail, so checking it at the right moment is genuinely useful — just not on every submission.
Two kinds of limit
These get conflated, and they are unrelated.
Submission limits are properties of the payload:
| Limit | Value |
|---|---|
| Maximum submission size | 5 MB |
| Maximum e-invoices per submission | 100 |
| Maximum size per e-invoice | 300 KB |
A batch has to satisfy all three, so 100 documents averaging more than 50 KB will hit the 5 MB ceiling before the document count.
Request rates are separate, and LHDN publishes them per endpoint as recommendations rather than as a single enforced number:
| Endpoint | Recommended rate, per Client ID |
|---|---|
| Login (taxpayer or intermediary) | 12 RPM |
| Submit Documents | 100 RPM |
| Get Submission | 300 RPM |
| Get Document Details | 125 RPM |
| Search Documents | 12 RPM, and around one request every 5 seconds per taxpayer |
| Get Recent Documents | 12 RPM |
| Cancel Document | 12 RPM |
Exceeding what the system will tolerate returns HTTP 429 with a Retry-After header. Handle that header rather than retrying immediately — a retry loop that ignores it makes the situation worse. The low login limit is the clearest argument for caching tokens: at 12 requests per minute, a system that authenticates per invoice will throttle itself long before it throttles anything else.
Sandbox and production
These are genuinely separate environments.
- Production:
api.myinvois.hasil.gov.my - Sandbox:
preprod-api.myinvois.hasil.gov.my
They need different Client IDs and Client Secrets. Production credentials do not work in the sandbox, and the reverse is equally true. Documents submitted to the sandbox are test data — they are not real e-invoices, they carry no legal effect, and nothing migrates between the environments. LHDN's Integration Practices page also states that sandbox data is retained for a maximum of three months and then permanently deleted, and that the sandbox has a lower API rate limit than production.
The portal side has its own preproduction environment for setting up and inspecting sandbox submissions; the portal guide covers getting into it. Build and test there first, and keep the environment choice in configuration rather than in code, so that pointing at production is a deployment decision rather than an edit.
Where integrations go wrong
Common production failures fall into a small number of categories:
- Token expiry. A 60-minute token, a long-running job, and no refresh — a
401partway through a batch. - Requesting tokens too often. The opposite failure, and it throttles at 12 RPM.
- Schema and version drift. A document type version is deactivated, or the SDK changes, and documents that worked last quarter stop validating.
- Invalid TIN or registration number. An invalid TIN or registration number can cause validation to fail, and is avoidable by checking the data when the buyer is created.
- Wrong codes. Classification codes, unit codes, tax types and currency codes are enumerated values, not free text.
- Duplicate submission. A retry after a timeout that actually succeeded, producing two validated invoices for one sale. Idempotency on your side, keyed to your own reference number, prevents this.
- Throttling. Usually caused by polling the wrong endpoint, or by treating Search Documents as a reconciliation tool.
- Transient failures. Networks and platforms have bad days. Retries need backoff and a dead-letter path, not an infinite loop.
What the specific validation errors mean is a subject of its own — common MyInvois rejection errors covers those. And corrections have a deadline: a validated document can be cancelled within 72 hours of validation with a mandatory reason, after which the correction has to be made through a credit, debit or refund note. The 72-hour cancellation window covers the timing rules, including the case where the buyer, not the supplier, is the one who cancels.
What to prepare
Before a developer starts, have these settled: the taxpayer's TIN and registration details, an ERP system registered in the MyInvois Portal with credentials issued, a signing plan and, where required, an organisation-level certificate held by you or your authorised provider, sandbox access, a decision on whether you are submitting as the taxpayer or as an intermediary, and a clear answer on where the UUID and status will be stored in your own schema.
Before you commission an integration, these are the questions worth asking a software provider:
- Do you submit to MyInvois directly, or through a partner or intermediary?
- Who holds the credentials and the digital certificate — us, or you?
- If we leave, do we keep our credentials and our validated document records?
- How do we see that a submission failed, and how quickly?
- Do you handle consolidated and self-billed documents, and adjustments to validated ones?
- What happens when LHDN changes the schema — who updates it, and at whose cost?
- Can we test in the sandbox before going live?
Question 2 decides more than it appears to. If your provider signs with their own certificate, that is normal and permitted — but it means changing provider is a migration, not a switch.
Build it, or buy something that already has it
This is a genuine question with a real answer on both sides.
Building is reasonable when volume is high enough that per-document fees matter, when invoices originate in a system nobody sells a connector for, or when you already run engineering capable of maintaining a compliance integration through schema changes for years.
Buying is reasonable — and is often the practical answer for businesses that need e-invoicing but do not want to maintain the integration themselves. The work does not end at go-live: certificates expire, schemas version, limits change, and the integration needs an owner for as long as the business issues invoices. The portal versus third-party apps sets out that comparison at length, and choosing accounting software covers what to look for more generally.
Finvo is being developed as Malaysian accounting software with a MyInvois submission workflow in the same system as its accounting records. That connection is separate from a public Finvo developer API; public developer access is not yet confirmed as available. Check current access and features during rollout.
Official documentation
Go to the primary sources for anything you are going to implement:
- MyInvois SDK — the reference for everything on this page
- Platform API — authentication, document types, notifications
- e-Invoicing API — submit, cancel, reject, retrieve, search
- Submit Documents — the limits and the 202 behaviour
- SDK FAQ — certificates, environments, throttling
- LHDN e-Invoice guidelines — the Guideline and Specific Guideline, currently v4.8 and v4.9
Related guides
- MyInvois Portal: how to log in, register and submit — where credentials are issued, and the free alternative
- What is MyInvois? — the system behind the endpoints
- The 55 mandatory fields — what goes inside the document
- Common MyInvois rejection errors — when validation comes back invalid
- The 72-hour cancellation window — cancel and reject semantics
- LHDN e-invoice compliance: requirements and checklist — the data work that has to happen first
