Skip to content

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 ID
csharp
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}`); // false
python
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']}")  # False
php
$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 false
csharp
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:

StatusDescription
is_ready: trueBuyer has TIN, ID type, and ID value - ready for LHDN
is_ready: falseMissing required fields - invoice submission will fail

ID Types ​

TypeDescriptionExample
BRNBusiness Registration Number202301012345 (SSM)
NRICMalaysian Identity Card901231145678 (MyKad)
PASSPORTPassport NumberA12345678
ARMYMilitary IDArmy 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 true
csharp
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 ​

FieldTypeDescription
namestringBusiness or individual name
tinstringTax Identification Number
id_typestringBRN, NRIC, PASSPORT, or ARMY
id_valuestringID number matching the type
address.line1stringStreet address
address.citystringCity name
address.statestringState code (from /states)
address.countryCodestringCountry code (from /countries)
contact.phonestringPhone (E.164 format)

Optional Fields ​

FieldTypeDescription
address.line2stringAddress line 2
address.line3stringAddress line 3
address.postCodestringPostal code
contact.emailstringEmail address
contact.namestringContact person name
contact.faxstringFax number (E.164 format)
is_draftbooleanCreate as draft buyer

Error Handling ​

StatusErrorDescription
401UNAUTHORIZEDInvalid or missing token
403FORBIDDENNo access to this company
404NOT_FOUNDBuyer doesn't exist
422VALIDATION_ERRORInvalid data provided
409CONFLICTCannot delete buyer with invoices

Next Steps ​

InvoisX - Malaysia's Leading e-Invoice Platform