Core Concepts
Key domain concepts for understanding the BizCARE Books e-invoicing API
Before integrating with the BizCARE Books e-Invoicing API, familiarize yourself with the core domain concepts that shape how e-invoicing works in Malaysia.
Company
A Company represents your business entity registered for e-invoicing with LHDN (Lembaga Hasil Dalam Negeri). Each user account has one company.
A company record stores:
- TIN (Tax Identification Number) -- Your LHDN-issued tax ID (e.g.,
C20948240010) - Registration number -- Your SSM business registration number or personal identification number
- Registration type -- One of
BRN(Business Registration Number),NRIC(National ID),PASSPORT, orARMY - LHDN credentials -- A
clientIdandclientSecretpair obtained from the MyInvois portal, used to authenticate document submissions with LHDN - Business details -- MSIC code, business activity description, SST registration number, address, and contact information
Your company must be fully set up before you can submit any invoices. Use GET /api/v1/companies and check the isCompanyReady flag to verify readiness.
The clientSecret is encrypted at rest using AES-256-GCM. Never share your LHDN credentials with third parties.
Invoice Types
BizCARE supports four invoice types, each serving a different purpose:
| Type | Description | Submittable |
|---|---|---|
INVOICE | Standard e-invoice issued by the supplier to the buyer | Yes |
SELF_BILLED_INVOICE | Invoice issued by the buyer on behalf of the supplier | Yes |
PENDING_FINALIZE_INVOICE | Draft invoice, not yet finalized | No |
PENDING_FINALIZE_SELF_BILLED_INVOICE | Draft self-billed invoice, not yet finalized | No |
Draft types (PENDING_FINALIZE_*) are working documents that cannot be submitted to LHDN. Change the type to INVOICE or SELF_BILLED_INVOICE when the invoice is ready for submission.
Adjustment Notes
Adjustment notes are corrections applied to a Valid invoice. They must always reference a parent invoice.
| Type | Purpose |
|---|---|
CREDIT_NOTE | Reduces the amount owed (e.g., partial return, discount applied after invoicing) |
DEBIT_NOTE | Increases the amount owed (e.g., undercharged amount, additional charges) |
REFUND_NOTE | Records a full or partial refund against the original invoice |
Each adjustment note has its own sequential code (separate from invoice codes) and contains line items describing the adjustment. To create an adjustment note, use POST /api/v1/invoices/:id/adjustment-note where :id is the parent invoice.
Consolidated Invoices
Consolidated invoices aggregate multiple transactions into a single LHDN submission. They are commonly used for:
- Daily POS (Point of Sale) sales summaries
- Batch processing of low-value transactions (under RM 10,000)
- Transactions where buyer details are not available
| Type | Description |
|---|---|
CONSOLIDATED_INVOICE | Aggregated standard invoice |
CONSOLIDATED_SELF_BILLED_INVOICE | Aggregated self-billed invoice |
Consolidation runs monthly on the server (see Monthly consolidation). Invoice responses carry isTotalExceedOrEqual10k so you can see which side of the RM 10,000 line an invoice falls on.
Document Lifecycle
Every invoice and adjustment note follows a defined lifecycle:
Draft --> Ready --> Submitted --> Valid / Invalid
| |
Cancelled Resubmit- Draft -- The document is created but not yet complete. The
isReadyflag isfalse. - Ready -- All required fields are populated. The
isReadyflag istrue. The document can now be submitted. - Submitted -- The document has been sent to LHDN and is awaiting validation. LHDN typically validates within seconds to minutes.
- Valid -- LHDN has accepted the document. It is now a legally binding e-invoice. Valid documents can be cancelled by providing a cancellation reason.
- Invalid -- LHDN has rejected the document. The rejection reasons are available in the submitted document's
failReasonandfailDetailsfields. You can fix the issues and resubmit.
You can skip the two-step create-then-submit flow by passing submitImmediately: true when creating an invoice. This creates the invoice and submits it to LHDN in a single request.
Buyer and Supplier
Every invoice contains two party objects representing the transaction participants:
- Supplier -- The party issuing the invoice. This is typically your company. The supplier object includes additional fields like
msic(MSIC code),businessActivityDescription, and optionallybankAccountandexporterCertifiedNumber. - Buyer -- The party receiving the goods or services. Your customer.
Both parties require:
| Field | Description |
|---|---|
name | Legal name of the business or individual |
tin | Tax Identification Number |
registrationType | One of BRN, NRIC, PASSPORT, ARMY |
registrationNumber | The corresponding registration number |
contactNumber | Phone number |
partyType | One of the values in Party types |
address | Object with addressLine0, cityName, state (a state code), country, and optional postalZone |
email | Email address (optional) |
When your company is set up, BizCARE can auto-populate the supplier (or buyer, for self-billed invoices) from your company profile.
Party types
partyType | Use for |
|---|---|
LOCAL_INDIVIDUAL | A person in Malaysia |
LOCAL_EXEMPTED_ENTITY | An exempted entity in Malaysia |
LOCAL_BUSINESS_AGENT_DEALER_DISTRIBUTOR | A business, agent, dealer or distributor in Malaysia |
FOREIGNER_BUSINESS | A business outside Malaysia |
FOREIGNER_INDIVIDUAL | A person outside Malaysia |
Malaysian state codes
address.state takes one of these LHDN codes:
| Code | State |
|---|---|
01 | Johor |
02 | Kedah |
03 | Kelantan |
04 | Melaka |
05 | Negeri Sembilan |
06 | Pahang |
07 | Pulau Pinang |
08 | Perak |
09 | Perlis |
10 | Selangor |
11 | Terengganu |
12 | Sabah |
13 | Sarawak |
14 | Wilayah Persekutuan Kuala Lumpur |
15 | Wilayah Persekutuan Labuan |
16 | Wilayah Persekutuan Putrajaya |
17 | Not Applicable |
Issue dates
invoiceDateTime.date (invoices) and adjustmentNoteIssueDate (adjustment notes) must be today or up to 3 days back on the Malaysian calendar. A future date is always refused. An older date fails with 400 VALIDATION_ERROR ("Issue date must be today or within the last 3 days, and cannot be in the future."). The examples in these docs use <today, YYYY-MM-DD> for this reason. Replace it with a real date in that window.
invoiceDateTime.time with a zone marker (14:30:00Z) is that exact instant. Without a marker (14:30:00) it is read as Malaysian time.
Line Items
Line items represent individual goods or services on an invoice. Each line item contains:
| Field | Description |
|---|---|
id | A unique identifier for the line item within the invoice |
description | Description of the good or service |
unit.count | Quantity |
unit.price | Unit price in MYR (or the invoice currency) |
unit.code | Unit of measure code (optional, e.g., "EA" for each) |
taxDetails | Array of tax entries, each with taxType and taxRate |
classifications | Product classification codes (optional) |
allowanceCharges | Line-level discounts or surcharges (optional) |
taxExemption | Tax exemption details if applicable (optional) |
Tax Details
Each line item must specify at least one tax detail entry:
{
"taxType": "01",
"taxRate": {
"percentage": 10
}
}The taxRate object supports either percentage (e.g., 10 for 10%) or ratePerUnit (a fixed amount per unit), depending on the tax type.
Tax Types
Malaysia's e-invoicing system uses the following tax type codes:
| Code | Description |
|---|---|
01 | Sales Tax |
02 | Service Tax |
03 | Tourism Tax |
04 | High-Value Goods Tax |
05 | Sales Tax on Low Value Goods |
06 | Not Applicable |
E | Tax Exempt |
Most businesses use tax type 01 (Sales Tax) or 02 (Service Tax). Use 06 for zero-rated or out-of-scope items, and E for items that are specifically exempt from tax.
LHDN Document Statuses
After submission to LHDN, each document is tracked with one of four statuses:
| Status | Description |
|---|---|
Submitted | The document has been sent to LHDN and is pending validation |
Valid | LHDN has accepted the document as a valid e-invoice |
Invalid | LHDN has rejected the document -- check failReason and failDetails for specifics |
Cancelled | The document was previously valid but has been cancelled by the issuer with a stated reason |
BizCARE automatically polls LHDN for status updates after submission (every 60 seconds while LHDN reports "in progress", then a half-hourly sweep for anything still Submitted after 10 minutes), and pushes changes to your webhooks. You can check the current status at any time: the latestSubmission object on GET /api/v1/invoices/:id carries it, and GET /api/v1/invoices/:id/submitted-documents gives the full history. POST /api/v1/submitted-documents/sync-status forces an immediate re-check.
When a document is marked Invalid, the failDetails field contains the LHDN validation errors in a structured format, allowing you to identify and fix the issue before resubmitting.