MyInvois API Integration: A Technical Guide
A practical guide to integrating Malaysia's IRBM MyInvois API — authentication, UBL XML, sandbox testing, error handling, and production go-live.
This guide is written for developers and IT leads responsible for building or overseeing MyInvois API integration. It covers the full integration lifecycle: obtaining credentials, structuring document payloads, submitting invoices, handling errors, and preparing for production go-live. If you are evaluating whether to use the MyInvois portal or the API, that decision is covered separately in our MyInvois vs API guide. This guide assumes you have decided to use the API and need to understand what implementation actually involves.
Prerequisites before starting: an IRBM MyInvois developer portal account, your business Tax Identification Number (TIN), API client credentials (client ID and client secret) issued by IRBM, and access to your ERP or billing system’s invoice data layer. You will also need to be registered on IRBM’s system as a taxpayer before sandbox integration will work correctly.
IRBM API Overview
The MyInvois API is a RESTful API with JSON and XML request body support and JSON responses. IRBM operates two environments:
- Sandbox (pre-production):
https://preprod.myinvois.hasil.gov.my - Production:
https://api.myinvois.hasil.gov.my
The sandbox environment is where all development and testing must happen. It mirrors the production API behaviour but uses test credentials and does not produce legally valid documents. Never test against the production environment — any document submitted to production is a legal tax document.
IRBM enforces rate limits on API calls. The exact per-minute and per-day limits are published in the IRBM developer documentation and may be adjusted over time. Your integration must implement rate-limit-aware submission logic — do not assume unlimited throughput, especially for batch submissions. At high invoice volumes (thousands per day), queuing and throttling at the application layer is mandatory.
IRBM uses API versioning through the request path. The current stable version is v1.0. Always specify the version explicitly in your endpoint paths. Do not construct version-agnostic base URLs; pin to a specific version and update intentionally when IRBM releases a new version.
Core endpoints:
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1.0/documentsubmissions | POST | Submit invoice document |
/api/v1.0/documentsubmissions/{submissionUID} | GET | Check submission status |
/api/v1.0/documents/{uuid}/raw | GET | Retrieve validated document |
/api/v1.0/documents/{uuid}/details | GET | Get document metadata |
/api/v1.0/documents/{uuid}/cancel | PUT | Cancel a submitted document |
Authentication: Client Certificate Setup
MyInvois uses OAuth 2.0 with client certificate mutual TLS (mTLS) authentication. This is stricter than standard OAuth flows — you cannot simply use a client ID and secret over HTTPS without a valid client certificate. Understanding this setup is critical; it is the most common cause of failed initial connections.
Obtaining your credentials: Register on the IRBM MyInvois developer portal (developers.myinvois.hasil.gov.my). Submit your business registration details and TIN. IRBM issues a client ID and client secret after verification. This process can take several business days.
Client certificate: Separately from the client ID and secret, IRBM requires a client certificate for mTLS. You generate a Certificate Signing Request (CSR) using your private key, submit it through the IRBM portal, and receive an IRBM-signed certificate. The certificate has a defined validity period (typically one year); set a calendar reminder for renewal at least 30 days before expiry. A lapsed certificate will cause all API calls to fail with a TLS handshake error.
Acquiring a token: The token endpoint is at /connect/token on the IRBM identity server. Use the client_credentials grant type:
import requests
def get_access_token(client_id, client_secret, cert_path, key_path):
token_url = "https://preprod.myinvois.hasil.gov.my/connect/token"
response = requests.post(
token_url,
data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret,
"scope": "InvoicingAPI"
},
cert=(cert_path, key_path), # mTLS client certificate
headers={"Content-Type": "application/x-www-form-urlencoded"}
)
response.raise_for_status()
token_data = response.json()
return token_data["access_token"], token_data["expires_in"]
Token caching: Tokens are valid for approximately 3600 seconds (one hour). Do not fetch a new token for every invoice submission — this wastes latency, increases load on the token endpoint, and risks hitting rate limits. Implement a token cache that stores the current token and its expiry timestamp. Before each API call, check whether the token has more than 60 seconds of remaining validity; if not, refresh it. This single optimisation makes a measurable difference in throughput for high-volume submissions.
Document Format: UBL XML Structure
IRBM accepts two document formats: UBL 2.1 XML and a simplified JSON schema. Both are legally equivalent. The choice between them depends on your integration context.
UBL 2.1 XML is the standard if you are adapting an existing PEPPOL integration or if your ERP already generates UBL XML for other markets. UBL is verbose but deeply standardised — there is comprehensive tooling, schema validation libraries, and cross-market documentation.
JSON format is simpler to construct, easier to validate with standard JSON tooling, and preferred for greenfield integrations where PEPPOL is not a parallel requirement. If you are building an integration from scratch for MyInvois only, JSON reduces implementation complexity.
For UBL XML, the document structure begins with the mandatory namespace declarations:
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
The mandatory top-level elements in sequence are:
cbc:UBLVersionID— must be2.1cbc:ID— your internal invoice numbercbc:IssueDate— formatYYYY-MM-DD(notDD/MM/YYYY— this is the most common date format mistake)cbc:IssueTime— formatHH:MM:SSZcbc:InvoiceTypeCode—01for standard invoice,02for credit note,03for debit notecbc:DocumentCurrencyCode— ISO 4217 currency code (e.g.,MYR,USD,SGD)cac:AccountingSupplierParty— your full business details including TIN, SST registration number, and addresscac:AccountingCustomerParty— buyer’s details including their TIN (mandatory for domestic buyers)cac:TaxTotal— tax summarycac:LegalMonetaryTotal— financial summary- One or more
cac:InvoiceLineelements
Tax handling requires specific attention. The TaxCategory element within TaxSubtotal uses IRBM-defined codes:
01— Standard-rated (SST 6% or applicable rate)02— Zero-rated03— Exempt04— Special category as defined by IRBM
All monetary amounts must be expressed with exactly two decimal places. Rounding inconsistencies between line-level amounts and document-level totals cause validation failures that can be difficult to diagnose if your calculation layer does not enforce consistent rounding rules.
Common UBL mistakes beyond date format and decimal precision: missing or incorrect namespace prefixes on child elements (every cac: and cbc: prefix must resolve to the correct namespace URI), incorrect TaxAmount calculation at TaxTotal level (must equal the sum of all TaxSubtotal/TaxAmount values), and missing InvoiceTypeCode (defaults are not applied — this field is always required).
Submission Workflow
With a valid token and a correctly structured document, the submission flow is as follows.
Submit the document via POST /api/v1.0/documentsubmissions. The request body is a JSON wrapper regardless of whether your underlying document is XML or JSON:
{
"documents": [
{
"format": "XML",
"document": "<base64-encoded UBL XML string>",
"documentHash": "<SHA-256 hash of the raw document before encoding>",
"codeNumber": "INV-2026-00123"
}
]
}
The documentHash is a SHA-256 hash of the raw document content (before base64 encoding). IRBM uses this for integrity verification. If your hash does not match the decoded document, the submission will be rejected immediately.
Interpreting the response: A successful submission returns HTTP 202 (Accepted) with a body containing:
{
"submissionUID": "abc123...",
"acceptedDocuments": [{ "uuid": "...", "invoiceCodeNumber": "INV-2026-00123" }],
"rejectedDocuments": []
}
HTTP 202 does not mean the invoice is validated — it means IRBM has accepted the submission for processing. Validation happens asynchronously for some submissions.
Checking submission status: Poll GET /api/v1.0/documentsubmissions/{submissionUID} to check the final status. The status field will transition from InProgress to Valid (fully validated) or Invalid (validation failed). For most single-document submissions this transition is near-instant; for bulk submissions it may take longer.
Retrieving the validated document: Once status is Valid, call GET /api/v1.0/documents/{uuid}/raw to retrieve the validated invoice. This response contains the original document with IRBM’s digital signature and QR code embedded. This is the legally valid invoice document that must be:
- Stored in your system linked to your internal invoice record.
- Transmitted to your buyer (either directly or via PEPPOL for cross-border).
- Archived for the minimum retention period required by IRBM (currently seven years).
Do not send your buyer the pre-validation invoice. The validated document — with QR code and UUID — is the legal instrument.
Error Handling Strategy
Error handling in MyInvois integration requires distinguishing between different failure categories, because the appropriate response varies significantly.
HTTP-level errors vs application-level errors: A submission that returns HTTP 202 but contains rejectedDocuments in the body is a validation failure — it is not a network or server error. Parse the response body to determine success, not just the HTTP status code.
Error categories and responses:
400 Bad Request— malformed request structure (missing required fields, invalid JSON/XML). Fix the data; do not retry without correction.401 Unauthorized— expired or invalid token. Refresh the token and retry.422 Unprocessable Entity— document failed IRBM validation rules. The response body contains specific error codes and field-level messages. Fix the document data; do not retry without correction.429 Too Many Requests— rate limit reached. Back off exponentially; retry after theRetry-Afterheader interval.500 / 503— IRBM server error. Retry with exponential backoff (start at 30 seconds, cap at 15 minutes). After three failed retries, route to dead letter queue.
Structured logging: For every submission attempt, log the following: internal invoice ID, IRBM submissionUID (if available), submission timestamp, HTTP status, error code (if applicable), error message, and retry count. This log is your audit trail for failed invoices and is essential when reconciling with IRBM records.
Dead letter queue: Invoices that fail validation (422) or fail submission three times (server errors) without successful correction should be routed to a dead letter queue — a holding state visible to your finance operations team. The queue should surface: the invoice reference, the IRBM error code, the error description, and the timestamp of last attempt. Finance staff need this to triage whether the issue is a data problem (wrong TIN, missing field) or a system problem.
Alerting: Any invoice that hits the dead letter queue should trigger a notification to finance operations. Any sustained pattern of 429 errors (more than 10 in a five-minute window) should alert the engineering team to a rate-limit breach.
Sandbox Testing Checklist
Complete all of the following in the sandbox environment before requesting production credentials from IRBM:
- Token acquisition working with sandbox client ID, secret, and certificate
- Supplier TIN registered and active in sandbox environment
- Standard invoice with all mandatory fields submits and returns
Validstatus - Validation failure test: submit invoice with missing buyer TIN; confirm
422response is parsed and error code logged correctly - Credit note submission referencing a previously validated invoice UUID
- Multi-currency invoice with exchange rate conversion to MYR
- Validated invoice retrieval: confirm QR code is embedded in the returned document
- Document retrieval and archival: confirmed validated invoice stored in your system with correct invoice record linkage
- Load test at expected peak daily volume — confirm no rate-limit failures at normal throughput
- Simulated 429 response handling: confirm exponential backoff and retry behaviour
- Dead letter queue routing: confirm failed invoice appears in review queue after three failed attempts
- End-to-end alert test: confirm finance team notification fires for a dead-letter invoice
Do not abbreviate this checklist. Gaps discovered in production — particularly in error handling and archival — are significantly more costly to resolve than gaps discovered in sandbox.
Production Go-Live Considerations
Going live with the production MyInvois API requires more than switching the base URL and credentials. Treat production go-live as a phased process.
Credential and certificate switch: Update the base URL from preprod.myinvois.hasil.gov.my to api.myinvois.hasil.gov.my. Replace sandbox credentials with production client ID, secret, and client certificate. Verify the certificate chain is correctly installed in your application environment.
Smoke test: Submit a real, low-value invoice as your first production submission. Verify the full flow: submission, status polling, validated document retrieval, archival, and delivery to the buyer. Do this with a transaction you can cancel if needed (IRBM allows cancellation within a time window post-submission).
First 48-hour monitoring: Assign someone to actively monitor the submission dashboard for the first 48 hours of production operation. Watch for unexpected validation failures, rate-limit warnings, and any invoices reaching the dead letter queue. Invoice data that passes sandbox testing sometimes reveals edge cases in production (different buyer TINs, unusual amounts, edge-case currencies).
On-call escalation path: Define and communicate the on-call escalation path before go-live. Who handles a midnight queue of 50 failed invoices? The answer should be documented, not improvised. Finance operations and engineering should have clear roles.
Certificate renewal: Set a reminder 60 days before your production client certificate expiry. Certificate renewal requires a new CSR submission to IRBM and processing time. A lapsed certificate causes a complete API outage with no workaround except manual portal submission — which is not operationally viable at volume.
Related Reading
- MyInvois E-Invoice Error Codes: What They Mean — Detailed reference for every MyInvois error code and how to fix it.
- MyInvois vs API Integration: Choosing Your E-Invoice Model — Decision guide for choosing between the portal and API pathway.
- How Nematix Handles E-Invoicing: From MyInvois to PEPPOL — How Nematix builds and maintains production MyInvois and PEPPOL integrations.
Ready to simplify your e-invoicing transition? Talk to our team about seamless MyInvois and PEPPOL integration for your business.