Malaysia v2: Create Receipt API
Create receipts for high-volume B2C sales and consolidate them into one e-invoice later, in the Malaysia LHDN API v2 (legacy): endpoint, headers, request fields, responses and code examples.
The Create Receipt API is for cases where issuing an e-invoice for every transaction is not practical, such as B2C (business-to-consumer) sales in supermarkets, retail stores and other high-volume businesses.
In a B2C flow, individual consumers make frequent, small purchases and usually do not need an e-invoice at the point of sale. A supermarket may serve thousands of customers a day, and an e-invoice for each sale would be impractical.
Instead, you issue receipts to customers during the day. A receipt is the customer’s proof of purchase, and you do not send each one to the tax authority straight away.
At the end of the day, or another period, the receipts are consolidated into a single e-invoice that summarizes all the transactions in that period. That e-invoice goes to the tax authority to meet the compliance requirements.
This approach:
- Saves work: you do not generate and submit an e-invoice for every B2C sale. Receipts are created at once, and the e-invoice is generated in bulk later.
- Keeps you compliant: a consolidated e-invoice at the end of each day, or another interval, meets the legal requirements.
- Keeps checkout fast: customers get their receipt at checkout.
It suits businesses with a high volume of low-value transactions.
You create a receipt by sending its data as JSON in a POST request.
Document types
| Code | Document | Value to send |
|---|---|---|
| 01 | Invoice | INV |
| 02 | Credit Note | CRD |
Endpoint
| Environment | Host |
|---|---|
| Sandbox | https://malaysia-sandbox.complyance.io |
| Production | https://malaysia-prod.complyance.io |
POST https://malaysia-sandbox.complyance.io/createReciept
POST https://malaysia-prod.complyance.io/createRecieptThe path is spelled createReciept.
Headers
| Header | Value | Description | Conditionality |
|---|---|---|---|
x-api-key | your-api-key | API key that authorizes the request | Mandatory |
Content-Type | application/json | Says the request body is JSON | Optional |
Code examples
These examples show the endpoint and headers. Send the request body as JSON.
curl --location 'https://malaysia-prod.complyance.io/createReciept' \
--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/createReciept', {
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-sandbox.complyance.io/createReciept', {}, headers
puts response.bodyimport requests
headers = {
'x-api-key': 'your-api-key',
'Content-Type': 'application/json'
}
response = requests.post('https://malaysia-prod.complyance.io/createReciept', 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/createReciept', [
'headers' => $headers
]);
echo $response->getBody()->getContents();
?>URL url = new URL("https://malaysia-prod.complyance.io/createReciept");
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/createReciept", 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
Send the receipts as a JSON array in receiptDataList. Each receipt number must be unique.
{
"receiptDataList": [
{
"documentType": "INV",
"recieptNumber": "RCPT-2025-0001",
"mobileNumber": "60123456789",
"originalEInvoiceReferenceNumber": "",
"recieptIssueDate": "2025-01-07",
"documentIssueTime": "22:30:00Z",
"typeOfBuyer": "BUSINESS",
"currency": "MYR",
"currencyExchangeRate": "",
"supplierId": "",
"sellerTinNumber": "C20000000000",
"sellerRegistrationIdType": "BRN",
"sellerRegistrationId": "202001234567",
"supplierSstRegistrationNumber": "",
"supplierTourismTaxRegistrationNumber": "",
"buyerId": "",
"buyerTinNumber": "",
"buyerRegistrationIdType": "",
"buyerRegistrationId": "",
"buyerSstRegistrationNumber": "",
"isShippingAndBuyerAddressSame": true,
"shippingRecipientName": "",
"shippingRecipientTin": "",
"shippingRecipientRegistrationType": "",
"shippingRecipientRegistrationNumber": "",
"totalExcludingTax": "700",
"taxTotal": "0",
"documentTotal": "700",
"invoiceAmountExemptedFromTax": "0",
"invoiceTaxExemptionReason": "Goods acquired with SST exemption under Sales Tax Act 2018. Reference No: (C01-2345-67890123)",
"invoiceAdditionalDiscountAmount": "0",
"invoiceAdditionalChargeAmount": "00",
"totalPayableAmount": "700",
"paymentMeans": "07",
"sellerAddress": {
"addressLine1": "Lot 66",
"addressLine2": "Bangunan Merdeka",
"addressLine3": "Persiaran Jaya",
"postalCode": "",
"city": "Kuala Lumpur",
"state": "08",
"country": "MYS"
},
"buyerAddress": {
"addressLine1": "",
"addressLine2": "",
"addressLine3": "",
"postalCode": "",
"city": "",
"state": "",
"country": ""
},
"shippingRecipientAddress": {
"addressLine1": "",
"addressLine2": " ",
"addressLine3": " ",
"postalCode": "",
"city": "",
"state": "",
"country": ""
},
"supplierDetails": {
"organizationName": "Acme Trading Sdn Bhd",
"email": "finance@acme.example",
"industryCode": "01111",
"industryDescription": "Growing of maize",
"phoneNumber": "60123456789"
},
"buyerDetails": {
"organizationName": "",
"email": "",
"phoneNumber": ""
},
"documentLineItems": [
{
"lineItemId": "1",
"commodityClassificationCode": "10",
"description": "Laptop peripherals",
"unitPrice": "100",
"quantity": "7",
"lineItemSubtotal": "700",
"discountPercent": "0",
"discountAmount": "0",
"chargePercent": "0",
"chargeAmount": "0",
"lineTotalExcludingTax": "700",
"taxType": "06",
"taxPercentage": "0",
"totalTax": "0",
"taxExemptionReason": "Goods acquired with SST exemption under Sales Tax Act 2018. Reference No: (C01-2345-67890123)",
"amountExemptedFromTax": "0",
"lineItemTotal": "700"
}
]
}
]
}Request fields
Receipt details
Each field below belongs to an object in receiptDataList.
| Field name | Conditionality | Description | Max length |
|---|---|---|---|
documentType | Mandatory | The document type (for example INV, CRD, DBT, RFD, SLF_INV, SLF_CRD, SLF_DBT, SLF_REF). | 3 to 7 |
recieptNumber | Mandatory | Receipt reference number for internal tracking. Example: test6. | 50 |
recieptIssuedate | Mandatory | Date the receipt is issued. Must be the current date. Format: yyyy-mm-dd. | 10 |
mobileNumber | Optional | Mobile number used to convert the receipt to an e-invoice. Example: +60123456789. | 15 |
originalEInvoiceReferenceNumber | Mandatory where applicable | LHDNM unique identifier number of the original invoice or document being adjusted. | 26 |
documentIssueDate | Mandatory | Date the e-invoice is issued. Must be the current date. | 10 (format: yyyy-mm-dd) |
typeOfBuyer | Mandatory | The type of buyer: BUSINESS for business entities or INDIVIDUAL for personal customers. | |
documentIssueTime | Mandatory | Time the e-invoice is issued. Must be UTC time. | 15 (format: hh:mm:ss) |
currency | Mandatory | The currency of the monetary values in the e-invoice. | 3 |
sellerTinNumber | Mandatory | Supplier’s TIN, assigned by LHDNM. | 14 |
sellerRegistrationIdType | Mandatory | Supplier’s registration, identification or passport number type. | |
sellerRegistrationId | Mandatory | For businesses: business registration number. For Malaysian individuals: MyKad or MyTentera identification number. For non-Malaysian individuals: passport number, MyPR or MyKAS identification number. MyPR and MyKAS use the NRIC scheme. | |
supplierSstRegistrationNumber | Mandatory where applicable | Supplier’s SST registration number. Not applicable to suppliers that are not SST-registered. Only the special characters dash (-) and semicolon (;) are allowed. Up to 2 SST numbers, separated by a semicolon. Enter “NA” if not SST-registered. | 35 |
supplierTourismTaxRegistrationNumber | Mandatory where applicable | Supplier’s tourism tax registration number. Only applies to registrants such as hotel operators. Only the special character dash (-) is allowed. Enter “NA” if not registered. | 17 |
totalExcludingTax | Mandatory | Sum of the amount payable, excluding taxes. Attach the currencyID attribute to the XML element. | |
taxTotal | Mandatory | Total amount of tax payable. | |
documentTotal | Mandatory | Invoice total amount including tax. | |
totalPayableAmount | Mandatory | Sum of the amount payable, including taxes and adjustments, excluding advance payments. Attach the currencyID attribute to the XML element. | |
paymentMeans | Optional | How funds are transferred (for example cash, cheque, bank transfer, credit card, e-wallet). | 2 |
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. |
Response
Success response
When the receipt is created, the API returns a success message.
{
"message": "Receipt saved successfully",
"data": null
}Error response
When something goes wrong, the API returns an error message. This example is for a receipt number that was already used.
{
"errorMessages": null,
"errorsList": null,
"batchId": null,
"errorCode": "409",
"success": true,
"valid": true,
"errors": [
{
"code": "E-RCPT-409",
"message": "RecieptNumber Random number -02 is already available with the status CREATED",
"location": "receiptDataList[0].recieptNumber",
"suggestion": "Use a different receipt number that hasn't been used before",
"affectedFields": [
"recieptNumber"
]
}
],
"metadata": {
"validationTime": "2025-06-03T09:43:25.569727Z[UTC]",
"totalErrors": 1
}
}Status codes
| Status code | Description |
|---|---|
200 | Success: the request was processed. |
202 | Accepted: the request was accepted and is still processing. |
Notes
- The
x-api-keymust be valid, or the request fails with an authentication error. - Check that all required fields are formatted correctly, especially dates and tax information.