Appearance
Buyers
This guide covers creating and managing buyers (customers) in InvoisX.
Setup
Before using the examples below, set up your HTTP client:
javascript
const API_URL = 'https://invoisx.com/api/v1';
const API_TOKEN = 'your-api-token';
async function api(method, endpoint, data = null) {
const response = await fetch(`${API_URL}${endpoint}`, {
method,
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: data ? JSON.stringify(data) : null,
});
return response.json();
}python
import requests
API_URL = 'https://invoisx.com/api/v1'
API_TOKEN = 'your-api-token'
def api(method, endpoint, data=None):
response = requests.request(
method,
f'{API_URL}{endpoint}',
headers={
'Authorization': f'Bearer {API_TOKEN}',
'Accept': 'application/json',
},
json=data
)
return response.json()php
use Illuminate\Support\Facades\Http;
$api = Http::withToken('your-api-token')
->accept('application/json')
->baseUrl('https://invoisx.com/api/v1');php
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => 'https://invoisx.com/api/v1/',
'headers' => [
'Authorization' => 'Bearer your-api-token',
'Accept' => 'application/json',
'Content-Type' => 'application/json',
]
]);java
import java.net.http.*;
import java.net.URI;
var client = HttpClient.newHttpClient();
var API_URL = "https://invoisx.com/api/v1";
var API_TOKEN = "your-api-token";
HttpResponse<String> api(String method, String endpoint, String jsonBody) throws Exception {
var builder = HttpRequest.newBuilder()
.uri(URI.create(API_URL + endpoint))
.header("Authorization", "Bearer " + API_TOKEN)
.header("Accept", "application/json")
.header("Content-Type", "application/json");
if (jsonBody != null) {
builder.method(method, HttpRequest.BodyPublishers.ofString(jsonBody));
} else {
builder.method(method, HttpRequest.BodyPublishers.noBody());
}
return client.send(builder.build(), HttpResponse.BodyHandlers.ofString());
}csharp
using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient {
BaseAddress = new Uri("https://invoisx.com/api/v1")
};
client.DefaultRequestHeaders.Add("Authorization", "Bearer your-api-token");
client.DefaultRequestHeaders.Add("Accept", "application/json");Overview
Buyers represent your customers who receive invoices. Each buyer has contact information, tax details, and address data required by LHDN for e-invoicing compliance.
Creating a Buyer
Complete Buyer
Create a buyer with all required LHDN fields:
javascript
const buyer = await api('POST', '/buyers', {
name: 'Acme Corporation Sdn Bhd',
tin: 'C12345678000',
id_type: 'BRN',
id_value: '202301012345',
address: {
line1: '123 Jalan Business',
line2: 'Suite 456',
city: 'Kuala Lumpur',
state: '14',
postCode: '50000',
countryCode: 'MYS'
},
contact: {
phone: '+60123456789',
email: 'billing@acme.com.my'
}
});
console.log(`Buyer ID: ${buyer.data.id}`);
console.log(`Is Ready: ${buyer.data.is_ready}`);python
buyer = api('POST', '/buyers', {
'name': 'Acme Corporation Sdn Bhd',
'tin': 'C12345678000',
'id_type': 'BRN',
'id_value': '202301012345',
'address': {
'line1': '123 Jalan Business',
'line2': 'Suite 456',
'city': 'Kuala Lumpur',
'state': '14',
'postCode': '50000',
'countryCode': 'MYS'
},
'contact': {
'phone': '+60123456789',
'email': 'billing@acme.com.my'
}
})
print(f"Buyer ID: {buyer['data']['id']}")
print(f"Is Ready: {buyer['data']['is_ready']}")php
$buyer = $api->post('/buyers', [
'name' => 'Acme Corporation Sdn Bhd',
'tin' => 'C12345678000',
'id_type' => 'BRN',
'id_value' => '202301012345',
'address' => [
'line1' => '123 Jalan Business',
'line2' => 'Suite 456',
'city' => 'Kuala Lumpur',
'state' => '14',
'postCode' => '50000',
'countryCode' => 'MYS'
],
'contact' => [
'phone' => '+60123456789',
'email' => 'billing@acme.com.my'
]
]);
echo "Buyer ID: {$buyer->json('data.id')}\n";
echo "Is Ready: " . ($buyer->json('data.is_ready') ? 'Yes' : 'No') . "\n";php
$response = $client->post('buyers', ['json' => [
'name' => 'Acme Corporation Sdn Bhd',
'tin' => 'C12345678000',
'id_type' => 'BRN',
'id_value' => '202301012345',
'address' => [
'line1' => '123 Jalan Business',
'line2' => 'Suite 456',
'city' => 'Kuala Lumpur',
'state' => '14',
'postCode' => '50000',
'countryCode' => 'MYS'
],
'contact' => [
'phone' => '+60123456789',
'email' => 'billing@acme.com.my'
]
]]);
$buyer = json_decode($response->getBody(), true);
echo "Buyer ID: {$buyer['data']['id']}\n";
echo "Is Ready: " . ($buyer['data']['is_ready'] ? 'Yes' : 'No') . "\n";java
var json = """
{
"name": "Acme Corporation Sdn Bhd",
"tin": "C12345678000",
"id_type": "BRN",
"id_value": "202301012345",
"address": {
"line1": "123 Jalan Business",
"line2": "Suite 456",
"city": "Kuala Lumpur",
"state": "14",
"postCode": "50000",
"countryCode": "MYS"
},
"contact": {
"phone": "+60123456789",
"email": "billing@acme.com.my"
}
}""";
var response = api("POST", "/buyers", json);
// Parse response.body() to get buyer IDcsharp
var buyer = new {
name = "Acme Corporation Sdn Bhd",
tin = "C12345678000",
id_type = "BRN",
id_value = "202301012345",
address = new {
line1 = "123 Jalan Business",
line2 = "Suite 456",
city = "Kuala Lumpur",
state = "14",
postCode = "50000",
countryCode = "MYS"
},
contact = new {
phone = "+60123456789",
email = "billing@acme.com.my"
}
};
var response = await client.PostAsJsonAsync("/buyers", buyer);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
var buyerId = result.GetProperty("data").GetProperty("id").GetString();
Console.WriteLine($"Buyer ID: {buyerId}");Draft Buyer
Create a buyer with minimal data for B2C scenarios. Draft buyers only require a name:
javascript
const draftBuyer = await api('POST', '/buyers', {
name: 'Walk-in Customer',
is_draft: true
});
// is_ready will be false
console.log(`Is Ready: ${draftBuyer.data.is_ready}`); // falsepython
draft_buyer = api('POST', '/buyers', {
'name': 'Walk-in Customer',
'is_draft': True
})
# is_ready will be false
print(f"Is Ready: {draft_buyer['data']['is_ready']}") # Falsephp
$draftBuyer = $api->post('/buyers', [
'name' => 'Walk-in Customer',
'is_draft' => true
]);
// is_ready will be false
echo "Is Ready: " . ($draftBuyer->json('data.is_ready') ? 'Yes' : 'No') . "\n";php
$response = $client->post('buyers', ['json' => [
'name' => 'Walk-in Customer',
'is_draft' => true
]]);
$draftBuyer = json_decode($response->getBody(), true);
// is_ready will be false
echo "Is Ready: " . ($draftBuyer['data']['is_ready'] ? 'Yes' : 'No') . "\n";java
var json = """
{"name": "Walk-in Customer", "is_draft": true}""";
var response = api("POST", "/buyers", json);
// is_ready will be falsecsharp
var draftBuyer = new { name = "Walk-in Customer", is_draft = true };
var response = await client.PostAsJsonAsync("/buyers", draftBuyer);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
// is_ready will be false
Console.WriteLine($"Is Ready: {result.GetProperty("data").GetProperty("is_ready")}");Draft Buyer with Partial Data
You can also create a draft with some fields populated:
json
{
"name": "Partial Customer",
"is_draft": true,
"id_type": "PASSPORT",
"id_value": "A12345678",
"contact": {
"phone": "+60123456789",
"email": "customer@example.com"
}
}Completing Draft Buyers
Use the update endpoint to add missing information and make the buyer ready for LHDN submission.
Understanding is_ready
The is_ready field indicates whether a buyer has complete data for LHDN submission:
| Status | Description |
|---|---|
is_ready: true | Buyer has TIN, ID type, and ID value - ready for LHDN |
is_ready: false | Missing required fields - invoice submission will fail |
ID Types
| Type | Description | Example |
|---|---|---|
BRN | Business Registration Number | 202301012345 (SSM) |
NRIC | Malaysian Identity Card | 901231145678 (MyKad) |
PASSPORT | Passport Number | A12345678 |
ARMY | Military ID | Army ID number |
Foreign Buyers
For buyers outside Malaysia, use state code 17 and the appropriate country code:
javascript
const foreignBuyer = await api('POST', '/buyers', {
name: 'Singapore Trading Pte Ltd',
tin: 'EI00000000020',
id_type: 'PASSPORT',
id_value: 'S1234567A',
address: {
line1: '123 Orchard Road',
city: 'Singapore',
state: '17', // Non-Malaysian
postCode: '238867',
countryCode: 'SGP' // Singapore
},
contact: {
phone: '+6591234567',
email: 'billing@singapore-trading.sg'
}
});python
foreign_buyer = api('POST', '/buyers', {
'name': 'Singapore Trading Pte Ltd',
'tin': 'EI00000000020',
'id_type': 'PASSPORT',
'id_value': 'S1234567A',
'address': {
'line1': '123 Orchard Road',
'city': 'Singapore',
'state': '17', # Non-Malaysian
'postCode': '238867',
'countryCode': 'SGP' # Singapore
},
'contact': {
'phone': '+6591234567',
'email': 'billing@singapore-trading.sg'
}
})php
$foreignBuyer = $api->post('/buyers', [
'name' => 'Singapore Trading Pte Ltd',
'tin' => 'EI00000000020',
'id_type' => 'PASSPORT',
'id_value' => 'S1234567A',
'address' => [
'line1' => '123 Orchard Road',
'city' => 'Singapore',
'state' => '17', // Non-Malaysian
'postCode' => '238867',
'countryCode' => 'SGP' // Singapore
],
'contact' => [
'phone' => '+6591234567',
'email' => 'billing@singapore-trading.sg'
]
]);php
$response = $client->post('buyers', ['json' => [
'name' => 'Singapore Trading Pte Ltd',
'tin' => 'EI00000000020',
'id_type' => 'PASSPORT',
'id_value' => 'S1234567A',
'address' => [
'line1' => '123 Orchard Road',
'city' => 'Singapore',
'state' => '17', // Non-Malaysian
'postCode' => '238867',
'countryCode' => 'SGP' // Singapore
],
'contact' => [
'phone' => '+6591234567',
'email' => 'billing@singapore-trading.sg'
]
]]);
$foreignBuyer = json_decode($response->getBody(), true);java
var json = """
{
"name": "Singapore Trading Pte Ltd",
"tin": "EI00000000020",
"id_type": "PASSPORT",
"id_value": "S1234567A",
"address": {
"line1": "123 Orchard Road",
"city": "Singapore",
"state": "17",
"postCode": "238867",
"countryCode": "SGP"
},
"contact": {
"phone": "+6591234567",
"email": "billing@singapore-trading.sg"
}
}""";
var response = api("POST", "/buyers", json);csharp
var foreignBuyer = new {
name = "Singapore Trading Pte Ltd",
tin = "EI00000000020",
id_type = "PASSPORT",
id_value = "S1234567A",
address = new {
line1 = "123 Orchard Road",
city = "Singapore",
state = "17", // Non-Malaysian
postCode = "238867",
countryCode = "SGP" // Singapore
},
contact = new {
phone = "+6591234567",
email = "billing@singapore-trading.sg"
}
};
var response = await client.PostAsJsonAsync("/buyers", foreignBuyer);Listing Buyers
javascript
// List all buyers
const buyers = await api('GET', '/buyers');
// With search
const filtered = await api('GET', '/buyers?search=Acme&per_page=10');python
# List all buyers
buyers = api('GET', '/buyers')
# With search
filtered = api('GET', '/buyers?search=Acme&per_page=10')php
// List all buyers
$buyers = $api->get('/buyers');
// With search
$filtered = $api->get('/buyers', [
'search' => 'Acme',
'per_page' => 10
]);php
// List all buyers
$response = $client->get('buyers');
$buyers = json_decode($response->getBody(), true);
// With search
$response = $client->get('buyers', ['query' => [
'search' => 'Acme',
'per_page' => 10
]]);
$filtered = json_decode($response->getBody(), true);java
// List all buyers
var response = api("GET", "/buyers", null);
// With search
var filtered = api("GET", "/buyers?search=Acme&per_page=10", null);csharp
// List all buyers
var response = await client.GetAsync("/buyers");
var buyers = await response.Content.ReadFromJsonAsync<JsonElement>();
// With search
var filtered = await client.GetAsync("/buyers?search=Acme&per_page=10");Getting a Single Buyer
javascript
const buyer = await api('GET', `/buyers/${buyerId}`);python
buyer = api('GET', f'/buyers/{buyer_id}')php
$buyer = $api->get("/buyers/$buyerId");php
$response = $client->get("buyers/$buyerId");
$buyer = json_decode($response->getBody(), true);java
var response = api("GET", "/buyers/" + buyerId, null);csharp
var response = await client.GetAsync($"/buyers/{buyerId}");
var buyer = await response.Content.ReadFromJsonAsync<JsonElement>();Updating a Buyer
Nested Objects
When updating nested objects (address, contact), you must send the complete object. Partial updates will replace the entire object.
javascript
const updated = await api('PUT', `/buyers/${buyerId}`, {
name: 'Acme Corporation Sdn Bhd (Updated)',
contact: {
phone: '+60198765432',
email: 'accounts@acme.com.my'
}
});python
updated = api('PUT', f'/buyers/{buyer_id}', {
'name': 'Acme Corporation Sdn Bhd (Updated)',
'contact': {
'phone': '+60198765432',
'email': 'accounts@acme.com.my'
}
})php
$updated = $api->put("/buyers/$buyerId", [
'name' => 'Acme Corporation Sdn Bhd (Updated)',
'contact' => [
'phone' => '+60198765432',
'email' => 'accounts@acme.com.my'
]
]);php
$response = $client->put("buyers/$buyerId", ['json' => [
'name' => 'Acme Corporation Sdn Bhd (Updated)',
'contact' => [
'phone' => '+60198765432',
'email' => 'accounts@acme.com.my'
]
]]);
$updated = json_decode($response->getBody(), true);java
var json = """
{
"name": "Acme Corporation Sdn Bhd (Updated)",
"contact": {
"phone": "+60198765432",
"email": "accounts@acme.com.my"
}
}""";
var response = api("PUT", "/buyers/" + buyerId, json);csharp
var update = new {
name = "Acme Corporation Sdn Bhd (Updated)",
contact = new {
phone = "+60198765432",
email = "accounts@acme.com.my"
}
};
var response = await client.PutAsJsonAsync($"/buyers/{buyerId}", update);Completing a Draft Buyer
javascript
const completed = await api('PUT', `/buyers/${buyerId}`, {
tin: 'C12345678000',
id_type: 'BRN',
id_value: '202301012345',
address: {
line1: '123 Jalan Business',
city: 'Kuala Lumpur',
state: '14',
countryCode: 'MYS'
},
contact: {
phone: '+60123456789'
}
});
// is_ready should now be true
console.log(`Is Ready: ${completed.data.is_ready}`);python
completed = api('PUT', f'/buyers/{buyer_id}', {
'tin': 'C12345678000',
'id_type': 'BRN',
'id_value': '202301012345',
'address': {
'line1': '123 Jalan Business',
'city': 'Kuala Lumpur',
'state': '14',
'countryCode': 'MYS'
},
'contact': {
'phone': '+60123456789'
}
})
# is_ready should now be true
print(f"Is Ready: {completed['data']['is_ready']}")php
$completed = $api->put("/buyers/$buyerId", [
'tin' => 'C12345678000',
'id_type' => 'BRN',
'id_value' => '202301012345',
'address' => [
'line1' => '123 Jalan Business',
'city' => 'Kuala Lumpur',
'state' => '14',
'countryCode' => 'MYS'
],
'contact' => [
'phone' => '+60123456789'
]
]);
// is_ready should now be true
echo "Is Ready: " . ($completed->json('data.is_ready') ? 'Yes' : 'No') . "\n";php
$response = $client->put("buyers/$buyerId", ['json' => [
'tin' => 'C12345678000',
'id_type' => 'BRN',
'id_value' => '202301012345',
'address' => [
'line1' => '123 Jalan Business',
'city' => 'Kuala Lumpur',
'state' => '14',
'countryCode' => 'MYS'
],
'contact' => [
'phone' => '+60123456789'
]
]]);
$completed = json_decode($response->getBody(), true);
// is_ready should now be true
echo "Is Ready: " . ($completed['data']['is_ready'] ? 'Yes' : 'No') . "\n";java
var json = """
{
"tin": "C12345678000",
"id_type": "BRN",
"id_value": "202301012345",
"address": {
"line1": "123 Jalan Business",
"city": "Kuala Lumpur",
"state": "14",
"countryCode": "MYS"
},
"contact": {
"phone": "+60123456789"
}
}""";
var response = api("PUT", "/buyers/" + buyerId, json);
// is_ready should now be truecsharp
var complete = new {
tin = "C12345678000",
id_type = "BRN",
id_value = "202301012345",
address = new {
line1 = "123 Jalan Business",
city = "Kuala Lumpur",
state = "14",
countryCode = "MYS"
},
contact = new {
phone = "+60123456789"
}
};
var response = await client.PutAsJsonAsync($"/buyers/{buyerId}", complete);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
// is_ready should now be true
Console.WriteLine($"Is Ready: {result.GetProperty("data").GetProperty("is_ready")}");Deleting a Buyer
WARNING
Buyers with existing invoices cannot be deleted.
javascript
await api('DELETE', `/buyers/${buyerId}`);python
api('DELETE', f'/buyers/{buyer_id}')php
$api->delete("/buyers/$buyerId");php
$client->delete("buyers/$buyerId");java
api("DELETE", "/buyers/" + buyerId, null);csharp
await client.DeleteAsync($"/buyers/{buyerId}");Buyer Fields Reference
Required Fields
| Field | Type | Description |
|---|---|---|
name | string | Business or individual name |
tin | string | Tax Identification Number |
id_type | string | BRN, NRIC, PASSPORT, or ARMY |
id_value | string | ID number matching the type |
address.line1 | string | Street address |
address.city | string | City name |
address.state | string | State code (from /states) |
address.countryCode | string | Country code (from /countries) |
contact.phone | string | Phone (E.164 format) |
Optional Fields
| Field | Type | Description |
|---|---|---|
address.line2 | string | Address line 2 |
address.line3 | string | Address line 3 |
address.postCode | string | Postal code |
contact.email | string | Email address |
contact.name | string | Contact person name |
contact.fax | string | Fax number (E.164 format) |
is_draft | boolean | Create as draft buyer |
Error Handling
| Status | Error | Description |
|---|---|---|
| 401 | UNAUTHORIZED | Invalid or missing token |
| 403 | FORBIDDEN | No access to this company |
| 404 | NOT_FOUND | Buyer doesn't exist |
| 422 | VALIDATION_ERROR | Invalid data provided |
| 409 | CONFLICT | Cannot delete buyer with invoices |
Next Steps
- Invoices - Create invoices for buyers
- Validation - Validate before submission
- Reference Codes - State codes, country codes
