Malaysia v2: LHDN Unify API
Validate and submit B2B invoices, credit notes, debit notes, refund notes and self-billed documents to LHDN with the Malaysia Unify API v2 (legacy): endpoint, headers, request fields and responses.
The Unify API validates and processes business-to-business (B2B) invoices for LHDN. It supports invoices, credit notes, debit notes, refund notes and self-billed documents, and checks them against the tax and invoicing rules.
Document types
| Code | Document | Value to send |
|---|---|---|
| 01 | Invoice | INV |
| 02 | Credit Note | CRD |
| 03 | Debit Note | DBT |
| 04 | Refund Note | RFD |
| 11 | Self-billed Invoice | SLF_INV |
| 12 | Self-billed Credit Note | SLF_CRD |
| 13 | Self-billed Debit Note | SLF_DBT |
| 14 | Self-billed Refund Note | SLF_REF |
Endpoint
| Environment | Host |
|---|---|
| Sandbox | https://malaysia-sandbox.complyance.io |
| Production | https://malaysia-prod.complyance.io |
POST https://malaysia-sandbox.complyance.io/unify
POST https://malaysia-prod.complyance.io/unifyThis endpoint validates and processes invoice data, including seller and buyer details, line items and tax information.
Headers
| Header | Type | Description | Example | Conditionality |
|---|---|---|---|---|
x-api-key | string | Your API key | your-api-key | Mandatory |
invoiceMethod | string | The invoice method, such as non-peppol or peppol | non-peppol | Optional |
Content-Type | string | Set as application/json | application/json | Optional |
Code examples
These examples show the endpoint and headers. Send the request body as JSON.
curl --location 'https://malaysia-prod.complyance.io/unify' \
--header 'x-api-key: your-api-key' \
--header 'Content-Type: application/json'const headers = {
'x-api-key': 'your-api-key',
'Content-Type': 'application/json'
};
fetch('https://malaysia-prod.complyance.io/unify', {
method: 'POST',
headers: headers
})
.then(function(response) {
return response.json();
}).then(function(body) {
console.log(body);
});require 'rest-client'
headers = {
'x-api-key' => 'your-api-key',
'Content-Type' => 'application/json'
}
response = RestClient.post 'https://malaysia-prod.complyance.io/unify', {}, headers
puts response.bodyimport requests
headers = {
'x-api-key': 'your-api-key',
'Content-Type': 'application/json'
}
response = requests.post('https://malaysia-prod.complyance.io/unify', headers=headers)
print(response.json())<?php
$headers = [
'x-api-key' => 'your-api-key',
'Content-Type' => 'application/json'
];
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://malaysia-prod.complyance.io/unify', [
'headers' => $headers
]);
echo $response->getBody()->getContents();
?>URL url = new URL("https://malaysia-prod.complyance.io/unify");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("x-api-key", "your-api-key");
con.setRequestProperty("Content-Type", "application/json");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());package main
import (
"net/http"
)
func main() {
headers := map[string][]string{
"x-api-key": []string{"your-api-key"},
"Content-Type": []string{"application/json"},
}
req, err := http.NewRequest("POST", "https://malaysia-prod.complyance.io/unify", nil)
if err != nil {
// Handle error
}
for key, values := range headers {
for _, value := range values {
req.Header.Add(key, value)
}
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
// Handle error
}
defer resp.Body.Close()
}Request body
{
"invoiceDataList": [
{
"documentType": "INV",
"documentId": "Invoice-01",
"originalEInvoiceReferenceNumber": "",
"documentIssueDate": "2025-01-06",
"documentIssueTime": "02:30:00Z",
"currency": "MYR",
"currencyExchangeRate": "1",
"supplierId": "1",
"sellerTinNumber": "C20000000000",
"sellerRegistrationIdType": "BRN",
"sellerRegistrationId": "202001234567",
"supplierSstRegistrationNumber": "A01-2345-67891012",
"supplierTourismTaxRegistrationNumber": "123-4567-89012345",
"buyerId": "1",
"buyerTinNumber": "C30000000000",
"buyerRegistrationIdType": "BRN",
"buyerRegistrationId": "201901234568",
"buyerSstRegistrationNumber": "234234234",
"isShippingAndBuyerAddressSame": false,
"shippingRecipientName": "Example Logistics Sdn Bhd",
"shippingRecipientTin": "C30000000000",
"shippingRecipientRegistrationType": "BRN",
"shippingRecipientRegistrationNumber": "201901234568",
"totalExcludingTax": "1000",
"taxTotal": "60",
"documentTotal": "1060",
"invoiceAmountExemptedFromTax": "0",
"invoiceTaxExemptionReason": "Goods acquired with SST exemption under Sales Tax Act 2018. Reference No: (C01-2345-67890123)",
"invoiceAdditionalDiscountAmount": "0",
"invoiceAdditionalChargeAmount": "0",
"totalPayableAmount": "1060",
"paymentMeans": "1",
"sellerAddress": {
"addressLine1": "Lot 66",
"addressLine2": "Bangunan Merdeka",
"addressLine3": "Persiaran Jaya",
"postalCode": "50480",
"city": "Kuala Lumpur",
"state": "14",
"country": "MYS"
},
"buyerAddress": {
"addressLine1": "Lot 66",
"addressLine2": "Bangunan Merdeka",
"addressLine3": "Persiaran Jaya",
"postalCode": "50480",
"city": "Kuala Lumpur",
"state": "14",
"country": "MYS"
},
"shippingRecipientAddress": {
"addressLine1": "Lot 66",
"addressLine2": "Bangunan Merdeka",
"addressLine3": "Persiaran Jaya",
"postalCode": "50480",
"city": "Kuala Lumpur",
"state": "14",
"country": "MYS"
},
"supplierDetails": {
"organizationName": "Acme Trading Sdn Bhd",
"email": "finance@acme.example",
"industryCode": "01111",
"industryDescription": "Growing of maize",
"phoneNumber": "+60-123456789"
},
"buyerDetails": {
"organizationName": "Example Buyer Sdn Bhd",
"email": "accounts@buyer.example",
"phoneNumber": "+60-123456789"
},
"documentLineItems": [
{
"lineItemId": "1",
"commodityClassificationCode": "1",
"description": "Laptop peripherals",
"unitPrice": "100",
"quantity": "10",
"lineItemSubtotal": "1000",
"discountPercent": "0",
"discountAmount": "0",
"chargePercent": "0",
"chargeAmount": "0",
"lineTotalExcludingTax": "1000",
"taxType": "1",
"taxPercentage": "6",
"totalTax": "60",
"taxExemptionReason": "Goods acquired with SST exemption under Sales Tax Act 2018. Reference No: (C01-2345-67890123)",
"amountExemptedFromTax": "0",
"lineItemTotal": "1060"
}
]
}
]
}Request fields
Invoice data list
| ObjectName | Field Name | Conditionality | Informatics | Field Max Length | Sample Value |
|---|---|---|---|---|---|
| invoiceDataList | documentType | Mandatory | Identify the document type (e.g., INV, CRD, DBT, RFD, SLF_INV, SLF_CRD, SLF_DBT, SLF_REF.) | 3 to 7 | |
| invoiceDataList | documentId | Mandatory | Document reference number used by Supplier for internal tracking purpose | 50 | |
| invoiceDataList | originalEInvoiceReferenceNumber | Mandatory where applicable | LHDNM Unique Identifier Number of the original invoice/document that is being affected/adjusted. | 26 | |
| invoiceDataList | documentIssueDate | Mandatory | Date of issuance of the e-Invoice (Note that the date must be the current date) | 10 (format: yyyy-mm-dd) | |
| invoiceDataList | documentIssueTime | Mandatory | Time of issuance of the e-Invoice (Note that the time must be the UTC time) | 15 (format: hh:mm:ss) | |
| invoiceDataList | currency | Mandatory | Specific currency that is used to represent the monetary value stated in the e-Invoice | 3 | |
| invoiceDataList | invoiceStartDate | Optional | Start date of the transaction interval | 10 (format: yyyy-mm-dd) | |
| invoiceDataList | invoiceEndDate | Optional | End date of the transaction interval | 10 (format: yyyy-mm-dd) | |
| invoiceDataList | invoiceFrequency | Optional | Frequency of the invoice (e.g., Daily, Weekly, Biweekly, Monthly, Bimonthly, Quarterly, Half-yearly, Yearly, Others / Not Applicable) | 50 | |
| invoiceDataList | supplierId | Optional | Identification Number of a Specific Supplier in an Invoice | 20 | |
| invoiceDataList | sellerTinNumber | Mandatory | Supplier’s TIN assigned by LHDNM | 14 | |
| invoiceDataList | sellerRegistrationIdType | Mandatory | Supplier’s Registration / Identification Number / Passport Number | ||
| invoiceDataList | sellerRegistrationId | Mandatory | For businesses: Business registration number. For Malaysian individual: MyKad / MyTentera identification number. For non-Malaysian individual: Passport number / MyPR / MyKAS identification number. Note: For MyPR and MyKAS to use NRIC scheme. | ||
| invoiceDataList | supplierSstRegistrationNumber | Mandatory where applicable | SST registration number of the Supplier. This is not applicable to Supplier that are not SST-registered. The input of special characters is not allowed, except for dash (-) and semicolon (;). A maximum of two SST registration numbers is allowed, separated by a semicolon. Supplier to input “NA” if supplier is not registered for SST. | 35 | |
| invoiceDataList | supplierTourismTaxRegistrationNumber | Mandatory where applicable | Tourism tax registration number of the Supplier. This is only applicable to tourism tax registrant, which may consist of hotel operators and online travel operators. The input of special characters is not allowed, except for dash (-). Supplier to input “NA” if supplier is not registered for tourism tax. | 17 | |
| invoiceDataList | buyerId | Optional | Identification Number of a Specific Buyer in an Invoice | ||
| invoiceDataList | buyerTinNumber | Mandatory | Buyer’s TIN assigned by LHDNM | 14 | |
| invoiceDataList | buyerRegistrationIdType | Mandatory | Buyer’s Registration / Identification Number / Passport Number | ||
| invoiceDataList | buyerSstRegistrationNumber | Mandatory | SST registration number of the Buyer. This is not applicable to Buyers that are not SST-registered. The input of special characters is not allowed, except for dash (-) and semicolon (;). A maximum of two SST registration numbers is allowed, separated by a semicolon. Supplier to input “NA” if buyer’s SST registration number is not available or not provided. | ||
| invoiceDataList | isShippingAndBuyerAddressSame | Mandatory | Indicates whether the shipping and buyer address are the same | Boolean value | |
| invoiceDataList | shippingRecipientName | Mandatory where applicable | Name of shipping recipient of the products included in the e-Invoice in a commercial transaction | 300 | |
| invoiceDataList | shippingRecipientTin | Mandatory where applicable | TIN of the shipping recipient assigned by LHDNM | 14 | |
| invoiceDataList | shippingRecipientRegistrationType | Mandatory where applicable | Supplier’s Registration / Identification Number / Passport Number | ||
| invoiceDataList | shippingRecipientRegistrationNumber | Mandatory where applicable | SST registration number of the Buyer. This is not applicable to Buyers that are not SST-registered. The input of special characters is not allowed, except for dash (-) and semicolon (;). A maximum of two SST registration numbers is allowed, separated by a semicolon. Supplier to input “NA” if buyer’s SST registration number is not available or not provided. | ||
| invoiceDataList | invoiceAdditionalDiscountAmount | Mandatory where applicable | Amount deducted from the original price of a product or service. Please add currencyID attribute to the XML element. | ||
| invoiceDataList | invoiceAdditionalChargeAmount | Mandatory where applicable | Charge associated with the product or service (be it in the form of percentage (%) or prevailing specified rate) imposed before tax. Please add currencyID attribute to the XML element. | ||
| invoiceDataList | totalExcludingTax | Mandatory | Sum of amount payable (inclusive of applicable discounts and charges), excluding any applicable taxes (e.g., sales tax, service tax). Please add currencyID attribute to the XML. | ||
| invoiceDataList | taxTotal | Mandatory | Total amount of tax payable | ||
| invoiceDataList | documentTotal | Mandatory | Invoice Total Amount Including Tax | ||
| invoiceDataList | invoiceAmountExemptedFromTax | Mandatory where applicable | Total amount of tax exempted for sales tax or service tax purposes on the invoice level. | ||
| invoiceDataList | invoiceTaxExemptionReason | Mandatory where applicable | Description of tax exemption applicable on the invoice level (e.g., Buyer’s sales tax exemption certificate number, special exemption as per gazette orders, etc.). The input is limited to the following special characters: period ”.”, dash ”-”, comma ”,”, and parenthesis ”()“. | ||
| invoiceDataList | totalPayableAmount | Mandatory | Sum of amount payable (inclusive of total taxes chargeable and any rounding adjustment) excluding any amount paid in advance. Please add currencyID attribute to the XML element. | ||
| invoiceDataList | paymentMeans | Optional | Chosen mechanism through which funds are transferred from buyer to supplier (e.g., cash, cheque, bank transfer, credit card, debit card, e-Wallet/ Digital Wallet, etc.) | 2 |
Supplier details
| ObjectName | Field Name | Conditionality | Informatics | Field Max Length | Sample Value |
|---|---|---|---|---|---|
| supplierDetails | organizationName | Mandatory | Name of business or individual who will be the supplier providing the goods / services in a commercial transaction. | 300 | |
| supplierDetails | Optional | E-mail address of the Supplier (Following the email standards (RFC 5321 and RFC 5322)). | 320 | ||
| supplierDetails | industryCode | Mandatory | 5-digit numeric code that represents the Supplier’s business nature and activity | 5 | |
| supplierDetails | industryDescription | Mandatory | Description of the Supplier’s business activity | 300 | |
| supplierDetails | phoneNumber | Mandatory | The telephone number of the Supplier (e.g., office, mobile, fax) | 20 |
Seller address
| ObjectName | Field Name | Conditionality | Informatics | Field Max Length | Sample Value |
|---|---|---|---|---|---|
| sellerAddress | addressLine1 | Mandatory | This is the main address line in an address structure that can be used to give the main address line information. A possible value for this field is “NA” and then all other address fields would not be provided except for the state field which would is mapped to the field. | 150 | |
| sellerAddress | addressLine2 | Optional | An additional address line in an address that can be used to give further details supplementing the main line. | 150 | |
| sellerAddress | addressLine3 | Optional | An additional address line in an address that can be used to give further details supplementing the main line. | 150 | |
| sellerAddress | postalCode | Optional | The identifier for an addressable group of properties according to the relevant postal service. | 50 | |
| sellerAddress | city | Mandatory | The common name of the city, town or village, where the Supplier, Buyer and Shipping Recipient address is located. | 50 | |
| sellerAddress | state | Mandatory | The state of a country. | 50 | |
| sellerAddress | country | Mandatory | A code that identifies the country. | 3 |
Buyer address
| ObjectName | Field Name | Conditionality | Informatics | Field Max Length | Sample Value |
|---|---|---|---|---|---|
| buyerAddress.addressLine1 | Address Line 1 | Mandatory | The main address line in an address structure. Input “NA” if unavailable | 150 | Lot 66 |
| buyerAddress.addressLine2 | Address Line 2 | Optional | An additional address line for further details | 150 | Bangunan Merdeka |
| buyerAddress.addressLine3 | Address Line 3 | Optional | An additional address line for further details | 150 | Persiaran Jaya |
| buyerAddress.postalCode | Postal Zone | Optional | The identifier for a postal zone | 50 | 50480 |
| buyerAddress.city | City Name | Mandatory | The common name of the city | 50 | Kuala Lumpur |
| buyerAddress.state | State | Mandatory | The state of a country | 50 | 14 |
| buyerAddress.country | Country | Mandatory | A code identifying the country | 3 | MYS |
Shipping recipient address
| ObjectName | Field Name | Conditionality | Informatics | Field Max Length | Sample Value |
|---|---|---|---|---|---|
| shippingRecipientAddress | addressLine1 | Mandatory where applicable | This is the main address line in an address structure that can be used to give the main address line information. A possible value for this field is “NA” and then all other address fields would not be provided except for the state field which would is mapped to the field. | 150 | |
| shippingRecipientAddress | addressLine2 | Optional | An additional address line in an address that can be used to give further details supplementing the main line. | 150 | |
| shippingRecipientAddress | addressLine3 | Optional | An additional address line in an address that can be used to give further details supplementing the main line. | 150 | |
| shippingRecipientAddress | postalCode | Optional | The identifier for an addressable group of properties according to the relevant postal service. | 50 | |
| shippingRecipientAddress | city | Mandatory where applicable | The common name of the city, town or village, where the Supplier, Buyer and Shipping Recipient address is located. | 50 | |
| shippingRecipientAddress | state | Mandatory where applicable | The state of a country. | 50 | |
| shippingRecipientAddress | country | Mandatory where applicable | A code that identifies the country. | 3 |
Line items
| ObjectName | Field Name | Conditionality | Informatics | Field Max Length | Sample Value |
|---|---|---|---|---|---|
| documentLineItems.lineItemId | Line ID | Optional | Identification of a Specific Line in an Invoice | 20 | 1 |
| documentLineItems.commodityClassificationCode | Classification | Mandatory | Category of products or services being billed | 3 | 1 |
| documentLineItems.description | Description of Product or Service | Mandatory | Details of products or services being billed | 300 | Laptop Peripherals |
| documentLineItems.unitPrice | Unit Price | Mandatory | Price assigned to a single unit of a product or service | 4 | |
| documentLineItems.quantity | Quantity | Optional | Number of units of a product or service | 1 | |
| documentLineItems.lineItemSubtotal | Subtotal | Mandatory | Amount of each individual item, excluding any taxes or charges | 100 | |
| documentLineItems.lineTotalExcludingTax | Total Excluding Tax | Mandatory | Sum of amount payable excluding any applicable taxes | 1436.5 | |
| documentLineItems.taxType | Tax Type | Mandatory | Type of taxes that will be applicable | 2 | 1 |
| documentLineItems.taxPercentage | Tax Rate | Mandatory | The appropriate tax rate that is applicable | 6 | |
| documentLineItems.totalTax | Tax Amount | Mandatory | The amount of tax payable | 292.2 | |
| documentLineItems.taxCode | Details of Tax Exemption | Optional | Description of tax exemption applicable | 300 | SST exemption |
| documentLineItems.taxExemptionReason | Amount Exempted from Tax | Conditional Mandatory | Total amount of tax exempted for SST purposes | 1460.5 | |
| documentLineItems.chargeAmount | Charge Amount | Optional | Charge associated with the product or service imposed after tax | 1000 | |
| documentLineItems.discountAmount | Discount Amount | Optional | Amount deducted from the original price of a product | 1000 | |
| documentLineItems.lineItemTotal | lineItemTotal | Mandatory | Sum of amount payable inclusive of total taxes chargeable | 1060 | |
| invoiceAdditionalChargeAmount | Optional | Additional Charges at Invoice Level | |||
| invoiceAdditionalDiscountAmount | Optional | Additional Discount at Invoice Level |
Invoice-level fields
| ObjectName | Field Name | Conditionality | Informatics | Field Max Length | Sample Value |
|---|---|---|---|---|---|
| invoiceAmountExemptedFromTax | Amount Exempted from Tax | Mandatory if tax exemption is applicable | Total amount of tax exempted for sales tax or service tax purposes. Please add currencyID attribute to the XML element. | 10 | |
| invoiceTaxExemptionReason | TaxExemptionReason | Mandatory if tax exemption is applicable | Description of tax exemption applicable on the invoice level. (e.g., Buyer’s sales tax exemption certificate number, special exemption as per gazette orders, etc.). | Goods acquired with SST exemption under Sales Tax Act 2018. Reference No: ABC.TAX(S)012-3/4/56(7) | |
| paymentMeans | PaymentMeansCode | Optional | Chosen mechanism through which funds are transferred from buyer to supplier (e.g., cash, cheque, bank transfer, credit card, debit card, e-Wallet/ Digital Wallet, etc.) | 1 | |
| invoiceAdditionalDiscountAmount | Discount Amount | Optional | Additional Charges at Invoice Level | 1000 | |
| totalExcludingTax | Total Excluding Tax | Mandatory | Sum of amount payable excluding any applicable taxes | 1436.5 | |
| taxTotal | Total Tax Amount | Mandatory | Total amount of tax payable | 1234 | |
| documentTotal | Invoice Total Amount Including Tax | Mandatory | Sum of amount payable inclusive of total taxes chargeable | 1436.5 | |
| totalPayableAmount | Total Payable Amount | Mandatory | Sum of amount payable excluding any amount paid in advance and rounding | 1436.5 |
Response
Response fields
| Parameter name | Type | Length | Description |
|---|---|---|---|
submissionUid | string | NA | The number LHDN generates as the official identifier for a submission. |
documentUlid | string | The number Complyance generates for the document, for tracking. | |
uuid | string | Government acknowledgement number for the invoice sent to LHDN. | |
invoiceCodeNumber | string | Document reference number the supplier uses for internal tracking. |
Success response
When the submission succeeds, the response lists the accepted documents. The xmlEncoded value is the Base64-encoded XML of the document, shortened here.
{
"submissionUid": "KMNPQRSTVW0123456789ABCD10",
"acceptedDocuments": [
{
"documentUlid": "01HZEXAMPLE000000000000001",
"uuid": "ABCDEFGHJK0123456789ABCD10",
"invoiceCodeNumber": "ML-ST-2424",
"xmlEncoded": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pgo…"
}
],
"rejectedDocuments": [],
"timestamp": "2023-08-14T08:15:30Z"
}Error response
When the submission fails, the response describes each error. See LHDN errors for the messages you can receive.
{
"errorMessages": null,
"errorsList": null,
"batchId": "00000000-0000-4000-8000-000000000000",
"errorCode": "400",
"success": true,
"valid": false,
"errors": [
{
"code": "E-SELR-05",
"message": "sellerRegistrationId cannot be empty",
"location": "invoiceDataList[0].sellerRegistrationId",
"suggestion": "Provide the seller's registration ID",
"affectedFields": [
"sellerRegistrationId"
]
}
]
}