Submit Your First Invoice
Step-by-step guide to creating and submitting an e-invoice to LHDN
This guide walks you through creating an invoice, submitting it to LHDN via the BizCARE Books e-Invoicing API, and checking its validation status.
Prerequisites
- Your company is registered and fully configured (see Getting Started)
- You have a valid API key (with
biz_prefix) - Your LHDN client credentials (
clientId/clientSecret) are set up on your company
Step 1: Verify Your Company Is Ready
Before creating an invoice, confirm that your company profile is complete and ready for submissions.
curl -X GET https://api.bizcare.my/api/v1/companies \
-H "X-Api-Key: biz_test_your-api-key"In the response, check that isCompanyReady is true:
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "TechVenture Sdn Bhd",
"tinCode": "C20948240010",
"registrationType": "BRN",
"registrationNumber": "202301045678",
"isCompanyReady": true,
"asBuyer": { ... },
"asSupplier": { ... }
}
}If isCompanyReady is false, you are missing required fields such as LHDN credentials, MSIC code, or address. Complete your company profile in the dashboard before proceeding.
Step 2: Create an Invoice
Create a standard invoice with buyer details and line items. Invoice codes are sequential integers unique to your company.
Replace the date placeholder
invoiceDateTime.date must be today or up to 3 days back on the Malaysian calendar. It can never be in the future. Replace <today, YYYY-MM-DD> in the examples below with a real date in that window, or the call fails with 400 VALIDATION_ERROR. See Issue dates.
curl -X POST https://api.bizcare.my/api/v1/invoices \
-H "X-Api-Key: biz_test_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"type": "INVOICE",
"invoiceCode": 1001,
"invoiceDateTime": {
"date": "<today, YYYY-MM-DD>",
"time": "14:30:00Z"
},
"supplier": {
"name": "TechVenture Sdn Bhd",
"tin": "C20948240010",
"registrationType": "BRN",
"registrationNumber": "202301045678",
"contactNumber": "+60312345678",
"email": "billing@techventure.com.my",
"partyType": "LOCAL_BUSINESS_AGENT_DEALER_DISTRIBUTOR",
"msic": "62011",
"businessActivityDescription": "Software development and IT consulting",
"address": {
"addressLine0": "Level 15, Menara TechVenture",
"addressLine1": "Jalan Bangsar",
"cityName": "Kuala Lumpur",
"state": "14",
"country": "MYS",
"postalZone": "59200"
}
},
"buyer": {
"name": "GlobalTrade Sdn Bhd",
"tin": "C25845670020",
"registrationType": "BRN",
"registrationNumber": "201901067890",
"contactNumber": "+60387654321",
"email": "accounts@globaltrade.com.my",
"partyType": "LOCAL_BUSINESS_AGENT_DEALER_DISTRIBUTOR",
"address": {
"addressLine0": "No. 42, Jalan Sultan Ismail",
"cityName": "Kuala Lumpur",
"state": "14",
"country": "MYS",
"postalZone": "50250"
}
},
"lineItems": [
{
"id": "1",
"description": "Custom ERP Module - Inventory Management",
"unit": {
"count": 1,
"price": 15000.00,
"code": "EA"
},
"taxDetails": [
{
"taxType": "01",
"taxRate": {
"percentage": 10
}
}
],
"classifications": ["022"]
},
{
"id": "2",
"description": "Annual Software Maintenance & Support",
"unit": {
"count": 12,
"price": 500.00,
"code": "MON"
},
"taxDetails": [
{
"taxType": "01",
"taxRate": {
"percentage": 10
}
}
],
"classifications": ["022"]
}
],
"payment": {
"mode": "03",
"terms": "Net 30"
}
}'A successful response returns the full invoice in data. Read data.id for the invoice ID. The example below is shortened:
{
"success": true,
"message": "Created successfully",
"data": {
"id": "f7e6d5c4-b3a2-1098-7654-321fedcba098",
"invoiceCode": 1001,
"type": "INVOICE",
"status": "Pending",
"latestSubmission": null
}
}Send an Idempotency-Key header on every create so a retry never makes a second invoice. If the code is already taken, you get 409 CODE_EXISTS. Invoice codes are unique across both test and live, so a test invoice with code 1001 blocks 1001 in live. See Error handling.
The supplier field is optional if your company profile is complete -- BizCARE will auto-populate it from your company details. You can override specific supplier fields by providing them explicitly.
Step 3: Submit to LHDN
Submit the invoice to LHDN for validation.
curl -X POST https://api.bizcare.my/api/v1/invoices/f7e6d5c4-b3a2-1098-7654-321fedcba098/submit-to-myinvois \
-H "X-Api-Key: biz_test_your-api-key"{
"success": true,
"message": "Submitted successfully",
"data": {
"submissionId": "HJSDHSA...",
"accepted": 1,
"rejected": 0,
"results": [
{ "invoiceId": "f7e6d5c4-b3a2-1098-7654-321fedcba098", "code": "1001", "outcome": "accepted" }
]
}
}HTTP 200 does not mean LHDN accepted the invoice
The call returns 200 even when LHDN rejects the document at intake. Check data.rejected and each results[].outcome (accepted or rejected, with a reason when rejected). Even an accepted result only means LHDN took the document for processing. The final answer (Valid or Invalid) comes later.
Demo organizations cannot submit to LHDN and get 409.
Step 4: Check Submission Status
Right after a submit, the invoice status is Submitted, not Valid. LHDN validates the document in the background, usually within seconds to minutes. Either poll as shown below, or use webhooks. See how statuses stay fresh.
Check the status by retrieving the submitted documents for your invoice.
curl -X GET https://api.bizcare.my/api/v1/invoices/f7e6d5c4-b3a2-1098-7654-321fedcba098/submitted-documents \
-H "X-Api-Key: biz_test_your-api-key"{
"data": [
{
"id": "d1c2b3a4-5678-90ab-cdef-123456789abc",
"uuid": "LHDN-DOC-UUID-HERE",
"status": "Valid",
"code": "1001",
"type": "INVOICE",
"longId": "LHDN-LONG-ID-FOR-PUBLIC-QUERIES",
"failReason": null,
"failDetails": null,
"createdAt": "2026-03-19T14:31:00.000Z"
}
]
}A Valid status means LHDN has accepted the invoice as a legally compliant e-invoice.
If the status is Invalid, check the failReason and failDetails fields for specific validation errors from LHDN, fix the issues, and resubmit.
Alternative: Create and Submit in One Step
You can combine invoice creation and submission into a single request by passing submitImmediately: true:
curl -X POST https://api.bizcare.my/api/v1/invoices \
-H "X-Api-Key: biz_test_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"type": "INVOICE",
"invoiceCode": 1002,
"invoiceDateTime": {
"date": "<today, YYYY-MM-DD>",
"time": "15:00:00Z"
},
"buyer": {
"name": "GlobalTrade Sdn Bhd",
"tin": "C25845670020",
"registrationType": "BRN",
"registrationNumber": "201901067890",
"contactNumber": "+60387654321",
"partyType": "LOCAL_BUSINESS_AGENT_DEALER_DISTRIBUTOR",
"address": {
"addressLine0": "No. 42, Jalan Sultan Ismail",
"cityName": "Kuala Lumpur",
"state": "14",
"country": "MYS",
"postalZone": "50250"
}
},
"lineItems": [
{
"id": "1",
"description": "IT Consulting Services - March 2026",
"unit": {
"count": 40,
"price": 250.00,
"code": "HUR"
},
"taxDetails": [
{
"taxType": "02",
"taxRate": {
"percentage": 8
}
}
]
}
],
"submitImmediately": true
}'The response data is the full invoice object (shortened here). Read data.id. The status is Submitted until LHDN validates it.
{
"success": true,
"message": "Submitted successfully",
"data": {
"id": "a9b8c7d6-e5f4-3210-9876-543210fedcba",
"invoiceCode": 1002,
"status": "Submitted",
"latestSubmission": { "status": "Submitted", "uuid": "..." }
}
}When using submitImmediately, if the invoice is created successfully but submission to LHDN fails, you will receive a response with "message": "Created but submission failed". The invoice still exists and you can submit it separately via the submit endpoint.