Skip to content

LHDN Integration APIs

APIs for integrating with the LHDN MyInvois platform directly. These endpoints proxy or wrap the official LHDN MyInvois APIs and require a valid company with an active LHDN intermediary token configured.

Base URL: https://api-etl.akaun.com/core2/tnt/dm/erp/e-invoice/lhdn-integrations

Required Permissions: API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_OWNER or API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_ADMIN

The fast path:

  1. Before invoicing a buyer, POST https://api-etl.akaun.com/core2/tnt/dm/erp/e-invoice/lhdn-integrations/tin-validation/backoffice-ep with tin, idType and idValue (API 1). envType defaults to SANDBOX: send PRODUCTION when you go live. isValid: false can mean a TIN and ID mismatch, not a missing TIN.
  2. If you do not know the TIN, POST …/tin-search/backoffice-ep with taxpayerName, or idType and idValue (more fields narrow the search, never widen it); envType again defaults to SANDBOX (API 2).
  3. To see why a submitted document failed, POST …/submission-document-details/backoffice-ep with documentUId or toIrbHdrGuid (API 3).

API 1 — Validate Taxpayer’s TIN

Validates whether a given TIN and ID combination is registered and active on the LHDN MyInvois system. Use this before invoicing a buyer to confirm their tax identity.

Endpoint

POST /tin-validation/backoffice-ep

Required Permission: API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_READ

Request Body

FieldTypeRequiredDescription
tinStringYesThe taxpayer’s TIN (Tax Identification Number) issued by LHDN
idTypeStringYesType of identification. Allowed values: NRIC, PASSPORT, BRN, ARMY
idValueStringYesThe actual identification document number corresponding to idType
envTypeStringNoLHDN environment to validate against. Allowed values: SANDBOX, PRODUCTION. Default: SANDBOX

ID Type Reference

idTypeDescription
NRICMalaysian National Registration Identity Card
PASSPORTPassport (for non-Malaysian individuals)
BRNBusiness Registration Number (for companies)
ARMYMalaysian Army ID

Example Request

{
  "tin": "C12345678900",
  "idType": "BRN",
  "idValue": "202301012345",
  "envType": "PRODUCTION"
}

Response Body

FieldTypeDescription
tinStringThe TIN that was validated
idTypeStringThe ID type used in the validation
idValueStringThe ID value used in the validation
isValidBooleantrue if the TIN and ID combination is valid on LHDN
validationMsgStringHuman-readable result or error message from LHDN
envTypeStringThe environment used for validation (SANDBOX or PRODUCTION)

Example Response

{
  "tin": "C12345678900",
  "idType": "BRN",
  "idValue": "202301012345",
  "isValid": true,
  "validationMsg": "TIN is valid.",
  "envType": "PRODUCTION"
}

Notes

  • This endpoint connects to the master database (app_cfg_main) to retrieve LHDN credentials, not the tenant database.
  • Always validate against PRODUCTION when going live. SANDBOX is for testing only.
  • A result of isValid: false does not necessarily mean the TIN does not exist — LHDN may return a mismatch between TIN and ID.

API 2 — Search Taxpayer’s TIN

Searches for a taxpayer’s TIN on LHDN MyInvois using their name, ID type/value, or both. Use this when you know partial identity information and need to discover the TIN.

Endpoint

POST /tin-search/backoffice-ep

Required Permission: API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_READ

Request Body

At least one of taxpayerName or the idType + idValue pair must be provided.

FieldTypeRequiredDescription
taxpayerNameStringConditionalFull or partial taxpayer name. Required if idType and idValue are not provided
idTypeStringConditionalType of identification: NRIC, PASSPORT, BRN, ARMY. Required if idValue is provided
idValueStringConditionalThe identification document number. Required if idType is provided
fileTypeStringNoDifferentiates individual vs non-individual taxpayers. 1 = individual (IG TIN), 2 = non-individual (non-IG TIN)
envTypeStringNoLHDN environment to search. Allowed values: SANDBOX, PRODUCTION. Default: SANDBOX

Supported Search Combinations

CombinationFields Required
By name onlytaxpayerName
By name + IDtaxpayerName, idType, idValue
By ID onlyidType, idValue
By ID + file typeidType, idValue, fileType
All fieldstaxpayerName, idType, idValue, fileType

Example Request

{
  "taxpayerName": "Acme Sdn Bhd",
  "idType": "BRN",
  "idValue": "202301012345",
  "envType": "PRODUCTION"
}

Response Body

FieldTypeDescription
tinStringThe TIN found for the given search criteria. Empty if not found
successBooleantrue if a TIN was found successfully
errorMessageStringError description if success is false
statusCodeIntegerHTTP status code from the LHDN API (e.g. 200, 400, 404)

Example Response (Success)

{
  "tin": "C12345678900",
  "success": true,
  "errorMessage": null,
  "statusCode": 200
}

Example Response (Not Found)

{
  "tin": null,
  "success": false,
  "errorMessage": "No taxpayer found matching the given criteria.",
  "statusCode": 404
}

Notes

  • This endpoint also uses master database credentials, not tenant-specific credentials.
  • When fileType is omitted, LHDN searches across both individual and non-individual taxpayers.
  • All search combinations use AND logic — additional fields narrow the results.

API 3 — Get Submission / Document Details

Retrieves the detailed status and validation results of a previously submitted e-invoice document from LHDN. Useful for checking why a document failed validation or confirming its final LHDN status.

Endpoint

POST /submission-document-details/backoffice-ep

Required Permission: API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_READ

Request Body

Provide either documentUId or toIrbHdrGuid (or both). At least one is required to identify the document.

FieldTypeRequiredDescription
documentUIdStringConditionalThe LHDN document UUID (also called longId) assigned at submission
toIrbHdrGuidUUIDConditionalInternal BigLedger to_irb header record GUID for the submitted document

Example Request

{
  "documentUId": "F9D425P6DS7D8IU",
  "toIrbHdrGuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Response Body

The response wraps either a detailsResponse (on success) or an error (on failure).

detailsResponse Object

FieldTypeDescription
uuidStringLHDN UUID of the document
submissionUidStringSubmission batch UID
longIdStringLHDN long ID (used in QR code / MyInvois portal link)
typeNameStringE-invoice type name (e.g. Invoice, Credit Note)
typeVersionNameStringE-invoice format version
issuerTinStringTIN of the supplier/issuer
issuerNameStringName of the issuer
receiverIdStringBuyer/receiver identification number
receiverNameStringBuyer/receiver company name
dateTimeIssuedStringISO 8601 date/time when the invoice was issued
dateTimeReceivedStringISO 8601 date/time when LHDN received the document
dateTimeValidatedStringISO 8601 date/time when LHDN validated the document
totalExcludingTaxDecimalTotal amount before tax
totalDiscountDecimalTotal discount amount
totalNetAmountDecimalNet total after discount
totalPayableAmountDecimalFinal payable amount including tax
statusStringCurrent LHDN document status (e.g. Valid, Invalid, Cancelled)
documentStatusReasonStringReason for status (e.g. rejection or cancellation reason)
cancelDateTimeStringISO 8601 cancellation datetime, if applicable
rejectRequestDateTimeStringISO 8601 rejection request datetime, if applicable
validationResultsObjectDetailed validation result object from LHDN (includes error codes and messages)
internalIdStringSupplier’s internal document reference number
createdByUserIdStringLHDN user ID that submitted the document

error Object

FieldTypeDescription
errorObjectPresent when LHDN returned an error. Contains error description and LHDN status code

Example Response (Success)

{
  "detailsResponse": {
    "uuid": "F9D425P6DS7D8IU",
    "submissionUid": "SUBM-0001",
    "longId": "XXXXXXXXXXXXXXXXXXXX",
    "typeName": "Invoice",
    "typeVersionName": "1.0",
    "issuerTin": "C12345678900",
    "issuerName": "My Company Sdn Bhd",
    "receiverId": "202301012345",
    "receiverName": "Acme Buyer Sdn Bhd",
    "dateTimeIssued": "2024-01-15T08:00:00Z",
    "dateTimeReceived": "2024-01-15T08:01:00Z",
    "dateTimeValidated": "2024-01-15T08:02:00Z",
    "totalExcludingTax": 1000.00,
    "totalDiscount": 50.00,
    "totalNetAmount": 950.00,
    "totalPayableAmount": 1008.00,
    "status": "Valid",
    "documentStatusReason": null,
    "cancelDateTime": null,
    "rejectRequestDateTime": null,
    "internalId": "INV-2024-001",
    "validationResults": null
  },
  "error": null,
  "envType": "PRODUCTION"
}

API 4 — Search Documents on LHDN

Queries e-invoice documents directly from LHDN MyInvois for the specified company. Returns a paginated list of documents matching the filter criteria.

Endpoint

POST /documents/{companyGuid}/backoffice-ep/query

Required Permission: API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_READ

Path Parameters

ParameterTypeRequiredDescription
companyGuidUUIDYesThe GUID of the company (bl_fi_mst_comp) whose LHDN intermediary token will be used to query documents

Query Parameters

The search criteria travel in the query string, not in a request body. The handler binds them without @RequestBody, so Spring fills them from query parameters and ignores any JSON body you send: a filter put in the body is silently dropped, and LHDN is searched as though you had sent no filter at all. The mapping still declares consumes = application/json, so send the Content-Type: application/json header (an empty body is fine).

Every parameter is optional. BigLedger forwards only the ones you send to LHDN’s document search and adds no defaults of its own, so an omitted page number or page size is whatever LHDN applies.

ParameterTypeDescription
uuidStringFilter by a specific LHDN document UUID
submissionDateFromInstantStart of the submission date range, in UTC, e.g. 2024-01-01T00:00:00Z
submissionDateToInstantEnd of the submission date range, in UTC
issueDateFromInstantStart of the issue date range, in UTC
issueDateToInstantEnd of the issue date range, in UTC
invoiceDirectionStringFilter by direction: Sent (outgoing) or Received (incoming)
statusStringFilter by LHDN document status (e.g. Valid, Invalid, Cancelled, Submitted)
documentTypeStringFilter by document type (e.g. 01 for Invoice, 02 for Credit Note)
searchQueryStringFree-text search against the document
pageNoIntegerPage number, passed to LHDN as sent
pageSizeIntegerResults per page, passed to LHDN as sent

Write the dates in UTC with a trailing Z, as in the example. A local time with an offset such as +08:00 puts a + in the query string, where an unencoded + reads as a space; convert to UTC instead.

Example Request

POST /documents/3fa85f64-5717-4562-b3fc-2c963f66afa6/backoffice-ep/query?submissionDateFrom=2024-01-01T00:00:00Z&submissionDateTo=2024-01-31T23:59:59Z&invoiceDirection=Sent&status=Valid&pageNo=1&pageSize=25
Content-Type: application/json

Response Body

FieldTypeDescription
resultArrayList of document objects (see fields below)
metadata.totalPagesIntegerTotal number of pages available
metadata.totalCountIntegerTotal number of matching documents
errorObjectPresent if LHDN returned an error

Each item in result

FieldTypeDescription
uuidStringLHDN document UUID
submissionUidStringBatch submission UID
longIdStringLHDN long ID
internalIdStringSupplier’s internal reference number
typeNameStringDocument type name (e.g. Invoice)
typeVersionNameStringFormat version
supplierTINStringSupplier TIN
supplierNameStringSupplier company name
buyerTINStringBuyer TIN
buyerNameStringBuyer company name
issuerTINStringIssuer TIN
issuerIDStringIssuer identification number
issuerIDTypeStringIssuer ID type
receiverTINStringReceiver TIN
receiverIDStringReceiver identification number
receiverNameStringReceiver name
receiverIDTypeStringReceiver ID type
dateTimeIssuedStringISO 8601 issue datetime
dateTimeReceivedStringISO 8601 received by LHDN datetime
dateTimeValidatedStringISO 8601 validated datetime
statusStringCurrent LHDN status
documentStatusReasonStringReason for status change
cancelDateTimeStringCancellation datetime (if applicable)
rejectRequestDateTimeStringRejection request datetime (if applicable)
submissionChannelStringHow the document was submitted (e.g. API)
intermediaryNameStringIntermediary company name
intermediaryTINStringIntermediary TIN
intermediaryROBStringIntermediary registration number
createdByUserIdStringLHDN user ID that submitted the document
documentCurrencyStringCurrency code (e.g. MYR)
totalExcludingTaxDecimalTotal before tax
totalDiscountDecimalTotal discounts
totalNetAmountDecimalNet total
totalPayableAmountDecimalFinal payable amount

Example Response

{
  "result": [
    {
      "uuid": "F9D425P6DS7D8IU",
      "submissionUid": "SUBM-0001",
      "longId": "XXXXXXXXXXXXXXXXXXXX",
      "internalId": "INV-2024-001",
      "typeName": "Invoice",
      "typeVersionName": "1.0",
      "supplierTIN": "C12345678900",
      "supplierName": "My Company Sdn Bhd",
      "buyerTIN": "C98765432100",
      "buyerName": "Acme Buyer Sdn Bhd",
      "dateTimeIssued": "2024-01-15T08:00:00Z",
      "dateTimeReceived": "2024-01-15T08:01:00Z",
      "dateTimeValidated": "2024-01-15T08:02:00Z",
      "status": "Valid",
      "documentCurrency": "MYR",
      "totalExcludingTax": 1000.00,
      "totalDiscount": 50.00,
      "totalNetAmount": 950.00,
      "totalPayableAmount": 1008.00
    }
  ],
  "metadata": {
    "totalPages": 5,
    "totalCount": 112
  },
  "error": null
}

Notes

  • The companyGuid in the path determines which LHDN intermediary token is used for authentication.
  • Documents returned are those associated with the company’s LHDN account (either as supplier or receiver, depending on invoiceDirection).
  • The same query-string criteria drive POST /documents/refresh-to-irb/{companyGuid}/backoffice-ep/query, which runs this search and then writes the status LHDN reports onto each of your e-invoice records whose LHDN document UUID is in the result. It needs API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_UPDATE, not READ.

API 5 — Read a taxpayer from an e-invoice QR code

POST /core2/tnt/dm/erp/e-invoice/lhdn-integrations/retrieve-tax-payer-by-qr-code/etl-ep

Controller: MyEInvoiceLHDNIntegrationController · Required Permission: API_TNT_DM_ERP_MY_E_INVOICE_LHDN_INTEGRATION_READ

This endpoint is live, not planned. It takes a picture of a taxpayer’s LHDN QR code, not the decoded text, as a multipart upload in the part imageFile. BigLedger reads the QR code out of the image, asks LHDN MyInvois who the taxpayer is, and returns what LHDN answers: TIN, name, identity, SST number, contact and address. The keys are LHDN’s, flat (tin, name, contactNumber, addressLine0), so map them yourself before filling einvoice_buyer_entity_hdr_json or einvoice_supplier_entity_hdr_json, whose fields are named differently.

Without an environment in the path it asks LHDN’s sandbox, not production. The /{envType} segment defaults to SANDBOX. For a real customer’s details call .../retrieve-tax-payer-by-qr-code/etl-ep/PRODUCTION.
curl -X POST "https://api-etl.akaun.com/core2/tnt/dm/erp/e-invoice/lhdn-integrations/retrieve-tax-payer-by-qr-code/etl-ep/PRODUCTION" \
  -H "AccessId: YOUR_ACCESS_ID" \
  -H "AccessKey: YOUR_ACCESS_KEY" \
  -H "tenantCode: YOUR_TENANT_CODE" \
  -F "imageFile=@customer-qr.png"
{
  "code": "OK_RESPONSE",
  "data": {
    "tin": "C2584563200",
    "name": "Syarikat Contoh Teknologi Sdn Bhd",
    "idType": "BRN",
    "idNumber": "202001234567",
    "email": "accounts@contohtek.example",
    "contactNumber": "+60312345678",
    "addressLine0": "Lot 12, Jalan Contoh 3",
    "postalZone": "47301",
    "city": "Petaling Jaya",
    "generatedTimestamp": "2026-10-21T09:15:02Z"
  },
  "message": ""
}

An unreadable image answers with the error “Unable to read the uploaded image file”. A picture without a readable QR code, or a refusal from LHDN, also answers with an error, whose wording varies. Sent as JSON instead of multipart, the call is refused before it reaches LHDN with 417 and “Content-Type ‘application/json’ is not supported”.

Last updated on