For authorized partners and integrators only. Do not distribute without permission from envoice.my.

envoice API

REST JSON Pro & Enterprise LHDN MyInvois

The envoice REST API lets third-party accounting software (Zoho Books, SQL Accounting, AutoCount, custom ERP) submit Malaysian e-invoices to LHDN MyInvois, manage your product catalog, and sync invoice data, without handling UBL, OAuth tokens, or LHDN credentials directly.

API access requires a Pro or Enterprise plan. Generate keys in Settings → API Keys.

Authentication

All requests must include an Authorization header with a Bearer token.

Authorization: Bearer env_a1b2c3d4e5f6...
Keep keys secret. Do not commit them to source control. Rotate immediately if compromised via Settings → API Keys → Revoke.

Base URL

https://envoice.my/api/v1

All endpoints below are relative to this base. HTTPS only.

Errors

All errors return JSON with an error field.

{ "error": "Only VALIDATED invoices can be cancelled" }

Rate Limits

LHDN enforces 300 documents/minute per TIN. No additional envoice-level limit beyond this.


Shops

Create Shop

Creates a new shop under your account. Use this to onboard a client programmatically without touching the web UI. Returns the new shop object plus a fresh API key for that shop. The API key is shown once and cannot be retrieved again.

POST /api/v1/shops

Request Body

FieldTypeRequiredDescription
namestringYesShop legal name (2-100 chars).
tinstringYesTax Identification Number.
brnstringYesBusiness Registration Number.
idTypestringNoAuto-derived from TIN prefix. One of BRN, NRIC, PASSPORT, ARMY.
msicCodestringYes5-digit MSIC code.
businessActivitystringYesBusiness activity description.
address1stringYesStreet address.
address2stringNoAddress line 2.
citystringYesCity.
statestringYes2-digit LHDN state code (e.g. 10 for Selangor).
postcodestringYes5-digit postcode.
emailstringYesShop contact email.
phonestringYesShop phone number.
apiKeyNamestringNoLabel for the generated API key (default: Default).

Example

curl -X POST https://envoice.my/api/v1/shops \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name":             "Syarikat Pelanggan Sdn Bhd",
    "tin":              "C12345678901",
    "brn":              "202301012345",
    "msicCode":         "46510",
    "businessActivity": "Wholesale of computers",
    "address1":         "No. 10, Jalan Teknologi",
    "city":             "Petaling Jaya",
    "state":            "10",
    "postcode":         "47810",
    "email":            "[email protected]",
    "phone":            "+60312345678",
    "apiKeyName":       "Zoho Books Integration"
  }'

Response

HTTP 201 Created.

{
  "shop": {
    "id":               "cm9x1...",
    "name":             "Syarikat Pelanggan Sdn Bhd",
    "tin":              "C12345678901",
    "brn":              "202301012345",
    "idType":           "BRN",
    "msicCode":         "46510",
    "businessActivity": "Wholesale of computers",
    "address":          "No. 10, Jalan Teknologi",
    "address2":         null,
    "city":             "Petaling Jaya",
    "state":            "10",
    "postcode":         "47810",
    "countryCode":      "MYS",
    "email":            "[email protected]",
    "phone":            "+60312345678",
    "sandboxMode":      true,
    "createdAt":        "2026-05-22T08:00:00.000Z"
  },
  "apiKey": "env_1a2b3c4d..."
}

Store the apiKey value securely. It is shown once and cannot be retrieved again. Use it in the Authorization header for all subsequent calls on behalf of this shop.

Get Shop

Returns the shop profile associated with your API key.

GET /api/v1/shop

Example

curl https://envoice.my/api/v1/shop \
  -H "Authorization: Bearer env_..."

Response

{
  "id":               "cm9x1...",
  "name":             "Syarikat ABC Sdn Bhd",
  "tin":              "C12345678900",
  "brn":              "202301012345",
  "msicCode":         "62010",
  "businessActivity": "Computer programming",
  "address":          "No. 1, Jalan Utama",
  "city":             "Kuala Lumpur",
  "state":            "14",
  "postcode":         "50000",
  "countryCode":      "MYS",
  "email":            "[email protected]",
  "phone":            "+60312345678",
  "sandboxMode":      false
}

Update Shop

Updates your shop profile. All fields are optional. Only the fields you include are changed.

PATCH /api/v1/shop

Request Body

FieldTypeDescription
namestringShop legal name (2-100 chars).
tinstringTax Identification Number.
brnstringBusiness Registration Number.
idTypestringBRN, NRIC, PASSPORT, or ARMY.
msicCodestring5-digit MSIC code.
businessActivitystringBusiness activity description.
address1stringStreet address.
address2stringAddress line 2 (optional).
citystringCity.
statestring2-digit LHDN state code.
postcodestring5-digit postcode.
emailstringShop contact email.
phonestringShop phone number.

Example

curl -X PATCH https://envoice.my/api/v1/shop \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+60312345678", "email": "[email protected]" }'
// HTTP 200 OK. Returns the updated shop object.

Invoices

List Invoices

Returns a paginated list of invoices for your shop, newest first.

GET /api/v1/invoices/list

Query Parameters

ParameterTypeDefaultDescription
limitnumber50Max records to return (max 200).
offsetnumber0Skip N records for pagination.
statusstringnoneFilter by status (e.g. VALIDATED, FAILED).

Example

curl "https://envoice.my/api/v1/invoices/list?limit=20&status=VALIDATED" \
  -H "Authorization: Bearer env_..."

Response

{
  "data": [
    {
      "id":            "cm9x1...",
      "invoiceNumber": "SHOP-20260301-0042",
      "status":        "VALIDATED",
      "buyerName":     "Syarikat ABC Sdn Bhd",
      "lhdnUuid":      "Z26ZTHTCHD2CE1...",
      "total":         "500.00",
      "currency":      "MYR",
      "createdAt":     "2026-03-01T09:15:00.000Z"
    }
  ],
  "limit":  20,
  "offset": 0
}

Submit Invoice

Creates and submits a new invoice to LHDN MyInvois.

POST /api/v1/invoices

Request Body

FieldTypeDescription
itemsrequiredarrayLine items. See Item Object. Min 1.
buyeroptionalobject | nullBuyer details. See Buyer Object. Null = B2C (no LHDN submission).
paymentModeoptionalstringLHDN payment code. Default "01" (cash).
currencyoptionalstringISO 4217. Default "MYR".
exchangeRateoptionalstringRequired when currency ≠ MYR.
idempotencyKeyoptionalstringUnique key per submission. Sending the same key twice returns the original invoice instead of creating a duplicate.

Example

curl -X POST https://envoice.my/api/v1/invoices \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{
    "buyer": {
      "tin": "C12345678900", "name": "Syarikat ABC Sdn Bhd",
      "idType": "BRN", "idValue": "202301012345",
      "phone": "+60123456789", "address": "No. 1, Jalan Utama",
      "city": "Kuala Lumpur", "postcode": "50000", "state": "14"
    },
    "items": [{
      "description": "Software Subscription",
      "classification": "022",
      "quantity": "1", "unitPrice": "500.00",
      "taxType": "06", "taxRate": "0"
    }],
    "paymentMode": "03",
    "idempotencyKey": "order-2026-03-001"
  }'

Response

// HTTP 201 Created
{
  "id":            "cm9x1...",
  "invoiceNumber": "SHOP-20260301-0042",
  "status":        "VALIDATED",
  "lhdnUuid":      "Z26ZTHTCHD2CE1R40EWRR5SK10",
  "lhdnQrLink":    "https://myinvois.hasil.gov.my/...",
  "total":         "500.00",
  "currency":      "MYR",
  "createdAt":     "2026-03-01T09:15:00.000Z"
}
Note: Status may be SUBMITTED immediately after creation. Poll GET /invoices/:id until VALIDATED. LHDN typically validates in 5–30 seconds.

Get Invoice

Returns a single invoice with full buyer and line item details.

GET /api/v1/invoices/:id

Example

curl https://envoice.my/api/v1/invoices/cm9x1... \
  -H "Authorization: Bearer env_..."

Response

{
  "id":            "cm9x1...",
  "invoiceNumber": "SHOP-20260301-0042",
  "status":        "VALIDATED",
  "lhdnUuid":      "Z26Z...",
  "lhdnQrLink":    "https://myinvois.hasil.gov.my/...",
  "buyer": { "tin": "C12345678900", "name": "...", "email": "..." },
  "items": [{ "description": "...", "quantity": "1", "lineTotal": "500.00" }],
  "total":     "500.00",
  "currency":  "MYR",
  "createdAt": "2026-03-01T09:15:00.000Z"
}

Cancel Invoice

Cancels a VALIDATED invoice at LHDN. Only within the 72-hour window.

POST /api/v1/invoices/:id/cancel

Request Body

FieldTypeDescription
reasonrequiredstringCancellation reason, min 5 characters. Sent to LHDN.

Example

curl -X POST https://envoice.my/api/v1/invoices/cm9x1.../cancel \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Wrong amount entered" }'
// HTTP 200 OK
{ "ok": true }
Irreversible. Cancelled invoices cannot be reinstated. Issue a new invoice if needed.

Refresh Invoice Status

Pulls the latest status from LHDN for a SUBMITTED invoice and updates it locally. Use this to poll after submission if the initial response was not yet VALIDATED.

POST /api/v1/invoices/:id/refresh

Example

curl -X POST https://envoice.my/api/v1/invoices/cm9x1.../refresh \
  -H "Authorization: Bearer env_..."

Response

{
  "id":          "cm9x1...",
  "status":      "VALIDATED",
  "lhdnUuid":    "Z26ZTHTCHD2CE1...",
  "lhdnQrLink":  "https://myinvois.hasil.gov.my/..."
}
Polling pattern: After POST /invoices returns SUBMITTED, call this endpoint every 3-5 seconds until status becomes VALIDATED or FAILED.

Download Invoice PDF

Returns the invoice as a PDF receipt. Useful for attaching to emails or storing in your accounting system.

GET /api/v1/invoices/:id/pdf

Response

Returns a PDF file with Content-Type: application/pdf.

curl https://envoice.my/api/v1/invoices/cm9x1.../pdf \
  -H "Authorization: Bearer env_..." \
  --output invoice.pdf

Issue Credit Note (Type 02)

Issues a credit note against a validated invoice. Use when you need to reduce the amount charged, for example to correct an overcharge or apply a discount after the original invoice was accepted by LHDN.

POST /api/v1/invoices/:id/credit-note
The referenced invoice must be VALIDATED and have a buyer TIN. Credit notes cannot be issued for general public invoices.

Request Body

Same structure as Submit Invoice. buyer is required.

Example

curl -X POST https://envoice.my/api/v1/invoices/cm9x1.../credit-note \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{ "buyer": { ... }, "items": [{ "description": "Pricing correction", "classification": "022", "quantity": "1", "unitPrice": "50.00", "taxRate": "0" }], "currency": "MYR" }'

Response

{
  "id":           "cm9x2...",
  "invoiceNumber": "SHOP-20260522-0002",
  "documentType":  "02",
  "billedInvoice": "Z26ZTHTCHD2CE1...",
  "status":        "VALIDATED",
  "total":         "50.00"
}

Issue Debit Note (Type 03)

Issues a debit note against a validated invoice. Use when you need to charge the buyer more, for example for additional services or delivery charges added after the original invoice.

POST /api/v1/invoices/:id/debit-note

Same rules and request body structure as the credit note endpoint.

Example

curl -X POST https://envoice.my/api/v1/invoices/cm9x1.../debit-note \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{ "buyer": { ... }, "items": [{ "description": "Additional delivery", "classification": "022", "quantity": "1", "unitPrice": "25.00", "taxRate": "0" }], "currency": "MYR" }'

Issue Refund Note (Type 04)

Issues a refund note against a validated invoice. Use when you have already refunded the buyer and need to record this in LHDN. Unlike a credit note (which reduces what is owed), a refund note documents money that has already been returned.

POST /api/v1/invoices/:id/refund-note

Same rules and request body structure as the credit note endpoint. If the original invoice is a self-billed invoice (type 11), a self-billed refund note (type 14) is issued automatically.

Example

curl -X POST https://envoice.my/api/v1/invoices/cm9x1.../refund-note \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{ "buyer": { ... }, "items": [{ "description": "Refund - order cancelled", "classification": "022", "quantity": "1", "unitPrice": "100.00", "taxRate": "0" }], "currency": "MYR" }'

Submit Self-Billed Invoice (Type 11)

A self-billed invoice is issued by the buyer on behalf of the supplier. This is common when paying freelancers, agents, or suppliers who cannot issue their own e-invoices. The buyer (your company) raises the document and submits it to LHDN.

POST /api/v1/invoices/self-billed

Request Body

FieldTypeDescription
supplierrequiredobjectThe supplier you are paying. Same fields as Buyer Object.
itemsrequiredarrayLine items. See Item Object.
paymentModestringDefault "01".
currencystringDefault "MYR".
exchangeRatestringRequired when currency is not MYR.

Example

curl -X POST https://envoice.my/api/v1/invoices/self-billed \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{
  "supplier": {
    "tin": "IG12345678901",
    "name": "Ahmad bin Ali",
    "idType": "NRIC",
    "idValue": "900101011234",
    "phone": "+60123456789",
    "address": "No. 3, Jalan Aman",
    "city": "Petaling Jaya",
    "postcode": "47810",
    "state": "10"
  },
  "items": [{
    "description": "Freelance consulting - April 2026",
    "classification": "022",
    "quantity": "1",
    "unitPrice": "3000.00",
    "taxRate": "0"
  }],
  "currency": "MYR"
}'

Raw Document (UBL JSON)

Returns the reconstructed UBL JSON document for an invoice. Useful for audit trail storage or passing to accounting software that understands LHDN's UBL format.

GET /api/v1/invoices/:id/document
curl https://envoice.my/api/v1/invoices/cm9x1.../document \
  -H "Authorization: Bearer env_..."

Response is the raw UBL JSON object (same format submitted to LHDN) with a Content-Disposition: attachment header for easy download.


Bulk Submit Invoices

Submit up to 20 invoices in a single request. Invoices are processed sequentially. Partial success is possible: check each result's success field.

POST /api/v1/invoices/bulk
curl -X POST https://envoice.my/api/v1/invoices/bulk \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{
  "invoices": [
    {
      "buyer": { "tin": "C123456789000", "name": "Acme Sdn Bhd", ... },
      "items": [{ "description": "Service", "classification": "022", "quantity": "1", "unitPrice": "500.00", "taxType": "06", "taxRate": "0" }],
      "paymentMode": "01"
    },
    {
      "buyer": null,
      "items": [{ "description": "Retail sale", "classification": "001", "quantity": "2", "unitPrice": "25.00", "taxType": "06", "taxRate": "0" }],
      "paymentMode": "03"
    }
  ]
}'

Response (HTTP 207):

{
  "total": 2,
  "succeeded": 2,
  "failed": 0,
  "results": [
    { "index": 0, "success": true, "data": { "id": "...", "status": "VALIDATED", ... } },
    { "index": 1, "success": true, "data": { "id": "...", "status": "PAID", ... } }
  ]
}
Invoices without a buyer ("buyer": null) are saved as PAID and batched into the monthly consolidated e-invoice. They do not consume your usage quota individually.

Consolidated

List Consolidated Invoices

Returns previously submitted consolidated e-invoices for your shop.

GET /api/v1/consolidated

Query parameters: limit (default 20, max 100), offset (default 0).

curl https://envoice.my/api/v1/consolidated \
  -H "Authorization: Bearer env_..."

Submit Consolidated Invoice

Submits a consolidated e-invoice to LHDN for all B2C sales (invoices without a buyer TIN) in the given period. If periodStart and periodEnd are omitted, the current calendar month is used.

POST /api/v1/consolidated
curl -X POST https://envoice.my/api/v1/consolidated \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{
  "periodStart": "2026-04-01T00:00:00.000Z",
  "periodEnd":   "2026-05-01T00:00:00.000Z"
}'
{
  "id":          "cm9x2...",
  "periodStart": "2026-04-01T00:00:00.000Z",
  "periodEnd":   "2026-05-01T00:00:00.000Z",
  "saleCount":   42,
  "totalAmount": "8450.00",
  "lhdnUuid":    "Z26ZTHTCHD2CE1...",
  "lhdnQrLink":  "https://myinvois.hasil.gov.my/...",
  "status":      "VALIDATED",
  "createdAt":   "2026-05-01T08:00:00.000Z"
}
Only invoices with status PAID and no buyer TIN that have not yet been consolidated are included. Running this twice for the same period is safe if the first run already consolidated all eligible sales.

Webhooks

Webhooks

Webhooks let envoice push invoice status changes to your server in real time, so you do not need to poll. Configure endpoints in Settings → Webhooks.

Retry policy: If your endpoint returns a non-2xx response or times out (10 seconds), the delivery is marked FAILED. Deliveries are not automatically retried, so design your endpoint to be idempotent.

Events

EventTriggered when
invoice.submittedInvoice accepted by LHDN, pending validation.
invoice.validatedLHDN validated the invoice. lhdnUuid and lhdnQrLink are available.
invoice.rejectedLHDN rejected the invoice.
invoice.cancelledInvoice cancelled at LHDN.

Signature Verification

Every webhook POST includes an X-Envoice-Signature header. Verify it to confirm the request came from envoice and was not tampered with.

X-Envoice-Signature: sha256=a3f1c2...

Compute the expected signature and compare:

// Node.js
const crypto = require('crypto');

function verifyWebhook(rawBody, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}
Use the raw request body for signature computation. Parsing JSON first and re-stringifying will change whitespace and break verification.

Payload Format

All webhook POSTs share the same envelope:

{
  "event":     "invoice.validated",
  "timestamp": "2026-05-22T10:30:00.000Z",
  "data": {
    "id":           "cm9x1...",
    "invoiceNumber": "SHOP-20260522-0001",
    "documentType":  "01",
    "status":        "VALIDATED",
    "lhdnUuid":      "Z26ZTHTCHD2CE1...",
    "lhdnQrLink":    "https://myinvois.hasil.gov.my/...",
    "total":         "100.00",
    "currency":      "MYR",
    "createdAt":     "2026-05-22T10:29:50.000Z"
  }
}

List Webhooks

Returns all webhook endpoints configured for your shop.

GET /api/v1/webhooks
curl https://envoice.my/api/v1/webhooks \
  -H "Authorization: Bearer env_..."
{
  "data": [
    {
      "id":        "whk_...",
      "url":       "https://your-server.com/webhook",
      "events":   ["invoice.validated", "invoice.rejected"],
      "active":    true,
      "createdAt": "2026-05-22T10:00:00.000Z"
    }
  ],
  "total": 1
}

Create Webhook

Register a new webhook endpoint. The secret returned is shown only once — store it immediately for signature verification.

POST /api/v1/webhooks
curl -X POST https://envoice.my/api/v1/webhooks \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://your-server.com/webhook",
  "events": ["invoice.validated", "invoice.rejected"],
  "active": true
}'
{
  "id":        "whk_...",
  "url":       "https://your-server.com/webhook",
  "events":   ["invoice.validated", "invoice.rejected"],
  "active":    true,
  "secret":    "whsec_a1b2c3...",
  "createdAt": "2026-05-22T10:00:00.000Z"
}

Maximum 10 webhooks per shop. URL must use HTTPS.

Update Webhook

Enable/disable a webhook or change its subscribed events.

PATCH /api/v1/webhooks/:id
curl -X PATCH https://envoice.my/api/v1/webhooks/whk_... \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{ "active": false }'

Delete Webhook

DELETE /api/v1/webhooks/:id
curl -X DELETE https://envoice.my/api/v1/webhooks/whk_... \
  -H "Authorization: Bearer env_..."

Catalog

List Products

Returns all products in your shop catalog.

GET /api/v1/catalog

Query Parameters

ParameterTypeDefaultDescription
limitnumber100Max records (max 500).
offsetnumber0Skip N records.
activebooleantrueSet to false to include deactivated products.

Example

curl https://envoice.my/api/v1/catalog \
  -H "Authorization: Bearer env_..."

Response

{
  "data": [
    {
      "id":             "cm9x1...",
      "sku":            "SW-MONTHLY",
      "name":           "Software Subscription (Monthly)",
      "description":   "Monthly SaaS license",
      "unitPrice":     "500.00",
      "classification": "022",
      "taxType":        "06",
      "taxRate":        "0.00",
      "unit":           "MON",
      "active":         true,
      "createdAt":      "2026-01-01T00:00:00.000Z"
    }
  ],
  "limit": 100, "offset": 0
}

Create Product

Adds a new product to the catalog. SKU must be unique within the shop.

POST /api/v1/catalog

Request Body

FieldTypeDescription
skurequiredstringUnique product code within the shop.
namerequiredstringProduct display name.
unitPricerequiredstringPrice per unit before tax (e.g. "500.00").
classificationrequiredstringLHDN classification code (e.g. "022").
descriptionoptionalstringProduct description.
taxTypeoptionalstringDefault "06" (exempt).
taxRateoptionalstringDefault "0".
unitoptionalstringLHDN unit code. Default "H87".

Example

curl -X POST https://envoice.my/api/v1/catalog \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{
    "sku": "SW-MONTHLY",
    "name": "Software Subscription (Monthly)",
    "unitPrice": "500.00",
    "classification": "022",
    "taxType": "06",
    "taxRate": "0",
    "unit": "MON"
  }'
// HTTP 201 Created. Returns the created product object.

Get Product

GET /api/v1/catalog/:id
curl https://envoice.my/api/v1/catalog/cm9x1... \
  -H "Authorization: Bearer env_..."

Update Product

Updates one or more fields of an existing product. Only fields included in the body are changed.

PUT /api/v1/catalog/:id

Request Body

All fields optional. Only provided fields are updated.

FieldTypeDescription
namestringProduct display name.
descriptionstringProduct description.
unitPricestringPrice per unit.
classificationstringLHDN classification code.
taxTypestringLHDN tax type code.
taxRatestringTax percentage.
unitstringLHDN unit code.
activebooleanSet to false to deactivate without deleting.

Example

curl -X PUT https://envoice.my/api/v1/catalog/cm9x1... \
  -H "Authorization: Bearer env_..." \
  -H "Content-Type: application/json" \
  -d '{ "unitPrice": "550.00" }'
// HTTP 200 OK. Returns the updated product object.

Delete Product

Deactivates a product (soft delete). Products are not hard-deleted because they may be referenced in past invoices. Deactivated products are excluded from catalog listings by default.

DELETE /api/v1/catalog/:id
curl -X DELETE https://envoice.my/api/v1/catalog/cm9x1... \
  -H "Authorization: Bearer env_..."
// HTTP 200 OK
{ "ok": true }

Buyer Object

Required for B2B submissions. Set to null for B2C / general public.

FieldTypeDescription
tinrequiredstringBuyer TIN. Use EI00000000010 for general public.
namerequiredstringBuyer legal name.
idTyperequiredstringBRN, NRIC, PASSPORT, or ARMY.
idValuerequiredstringID number matching idType.
phonerequiredstringPhone with country code (e.g. +60123456789).
addressrequiredstringStreet address.
cityrequiredstringCity.
postcoderequiredstringPostcode.
staterequiredstringLHDN state code (e.g. "14" = KL).
emailoptionalstringBuyer email.
countryCodeoptionalstringISO 3166-1 alpha-3. Default "MYS".

Item Object

FieldTypeDescription
descriptionrequiredstringLine item description.
classificationrequiredstringLHDN product/service classification code.
quantityrequiredstringQuantity (e.g. "2", "1.5").
unitPricerequiredstringPrice per unit before tax.
unitoptionalstringLHDN unit code. Default "H87". Common: "MON", "HUR".
taxTypeoptionalstringDefault "06" (exempt). Use "01" for SST 6%.
taxRateoptionalstringTax percentage. Default "0".

Invoice Status Values

StatusDescription
DRAFTCreated locally with no buyer. No LHDN submission.
PAIDB2C sale marked paid, no LHDN submission.
SUBMITTINGSubmission in progress.
SUBMITTEDAccepted by LHDN, pending validation.
VALIDATEDValidated by LHDN. lhdnUuid and lhdnQrLink populated.
FAILEDLHDN rejected the submission.
CANCELLEDCancelled at LHDN within 72-hour window.
Polling tip: Poll GET /api/v1/invoices/:id every few seconds after SUBMITTED. LHDN typically validates in 5–30 seconds.

Document Types

CodeNameEndpoint
01InvoicePOST /api/v1/invoices
02Credit NotePOST /api/v1/invoices/:id/credit-note
03Debit NotePOST /api/v1/invoices/:id/debit-note
04Refund NotePOST /api/v1/invoices/:id/refund-note
11Self-Billed InvoicePOST /api/v1/invoices/self-billed
12Self-Billed Credit NoteAuto-issued via credit-note endpoint on type 11
13Self-Billed Debit NoteAuto-issued via debit-note endpoint on type 11
14Self-Billed Refund NoteAuto-issued via refund-note endpoint on type 11

envoice.my. Malaysian e-Invoicing Platform. [email protected]