Integration Guide
Connect your system with our e-invoice API in 5 minutes.
How It Works
When your system creates an invoice for a customer, you call our API and we handle the rest — LHDN validation, digital signing, submission, and status tracking. You get back a confirmation and we handle all the compliance.
Get Your Credentials
- a. Create an account on InvoisKita and verify your email.
- b. Go to Settings → Company Profile and configure your LHDN connection (Client ID, Client Secret, TIN, etc.).
-
c.
Go to Settings → API Access and click Generate. Give it a name like
"My Accounting System". - d. Copy both values — User Secret (public identifier) and Secret Key (private). The Secret Key is shown only once.
# You'll use both values for authentication: User Secret: 1 Secret Key: 1|abc123def456...
Choose Sandbox or Live
Test your integration in the sandbox environment before going live.
Sandbox (Testing)
- • Free to test — no limit on test invoices
- • Uses LHDN pre-production API
- • Invoices are NOT legally binding
- • Same API — just flip the toggle
Production (Live)
- • Real invoices submitted to LHDN
- • Uses LHDN production API
- • Counts toward your plan invoice limit
- • Legally compliant e-invoices
How to switch
In Settings → Company Profile, you can set your LHDN connection to Sandbox or Production. While in sandbox mode, all API calls will submit to LHDN's test environment. Generate separate connections for each environment if needed.
API Base URL
https://invoiskita.com/api
All endpoints are prefixed with this base URL. The sandbox/live routing happens automatically based on your profile settings — you don't need a different URL.
Authenticate
Use the User Secret and Secret Key pair with Basic Auth. No separate login step needed:
curl https://invoiskita.com/api/me \ -u "USER_SECRET:SECRET_KEY"
Replace USER_SECRET with your User Secret (e.g. 1) and SECRET_KEY with your Secret Key.
Response:
{
"user": { "id": 1, "name": "John", "email": "john@example.com" },
"tenant": { "plan": "starter", "invoice_used": 12, "invoice_limit": 500 }
}
Or use the Bearer token directly (just the Secret Key):
curl https://invoiskita.com/api/invoices \ -H "Authorization: Bearer SECRET_KEY"
💡 Tip: Generate separate credentials for each integration (e.g. one for your accounting system, one for your POS). Revoke individual credentials from Settings → API Access without affecting others.
Submit Your First Invoice
Send invoice data from your system. We create the invoice and queue it for LHDN submission.
curl -X POST https://invoiskita.com/api/invoices \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"internal_receipt_number": "INV-2026-001",
"buyer_name": "Acme Sdn Bhd",
"buyer_tin": "C1234567890",
"items": [
{
"description": "Web Development Services",
"quantity": 1,
"unit_price": 5000.00
}
]
}'
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
| internal_receipt_number | string | Yes | Your invoice number (e.g. INV-2026-001) |
| buyer_name | string | Yes | Buyer's legal name |
| buyer_tin | string | No | TIN. Leave blank or use EI00000000010 for individuals (auto-sets NRIC) |
| buyer_id_type | string | No | BRN, NRIC, PASSPORT, or ARMY |
| buyer_registration_number | string | No | Registration number. Defaults to NA |
| items | array | Yes | Array of line items (see below) |
Line Item Fields
| Field | Type | Required | Description |
|---|---|---|---|
| description | string | Yes | Item description |
| quantity | number | Yes | Quantity (must be greater than 0) |
| unit_price | number | Yes | Price per unit (RM) |
| tax_type | string | No | Defaults to 06 (standard rate) |
Response (201 Created):
{
"message": "Invoice #INV-2026-001 created and queued for LHDN submission.",
"invoice": {
"id": 1,
"internal_receipt_number": "INV-2026-001",
"buyer_name": "Acme Sdn Bhd",
"buyer_tin": "C1234567890",
"status": "Draft",
"total_amount": 5000.00,
"items": [...]
}
}
Check Invoice Status
Track the LHDN submission status of your invoice:
curl https://invoiskita.com/api/invoices/1 \ -H "Authorization: Bearer YOUR_TOKEN"
The status field shows: Draft → Submitted → Approved / Rejected. If rejected, check validation_results for details.
Sample Code
PHP (cURL)
$ch = curl_init('https://invoiskita.com/api/invoices');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
],
CURLOPT_USERPWD => 'USER_SECRET:SECRET_KEY',
CURLOPT_POSTFIELDS => json_encode([
'internal_receipt_number' => 'INV-2026-001',
'buyer_name' => 'Acme Sdn Bhd',
'items' => [
['description' => 'Consulting', 'quantity' => 1, 'unit_price' => 500]
],
]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
Python
import requests
response = requests.post(
'https://invoiskita.com/api/invoices',
auth=('USER_SECRET', 'SECRET_KEY'),
json={
'internal_receipt_number': 'INV-2026-001',
'buyer_name': 'Acme Sdn Bhd',
'items': [
{'description': 'Consulting', 'quantity': 1, 'unit_price': 500}
],
}
)
print(response.json())
JavaScript / Node.js
const credentials = btoa('USER_SECRET:SECRET_KEY');
const response = await fetch('https://invoiskita.com/api/invoices', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + credentials,
'Content-Type': 'application/json',
},
body: JSON.stringify({
internal_receipt_number: 'INV-2026-001',
buyer_name: 'Acme Sdn Bhd',
items: [
{ description: 'Consulting', quantity: 1, unit_price: 500 }
],
}),
});
const data = await response.json();
Quick Reference
| Method | Endpoint | Description |
|---|---|---|
| GET | https://invoiskita.com/api/me | Your profile & usage |
| POST | https://invoiskita.com/api/invoices | Create invoice |
| GET | https://invoiskita.com/api/invoices/{id} | Invoice details |
| GET | https://invoiskita.com/api/invoices | List invoices |
| POST | https://invoiskita.com/api/invoices/{id}/submit | Submit to LHDN |
| POST | https://invoiskita.com/api/invoices/upload | CSV bulk upload |
| GET | https://invoiskita.com/api/customers | List customers |
| POST | https://invoiskita.com/api/customers | Create customer |
Need Help?
Contact our support team or check the full API Documentation for detailed endpoint specs.