Contacts
Invoa API contacts endpoints: list and search customers and suppliers, retrieve a contact with balances and history, create and update contacts.
Contacts are the customers and suppliers you bill. Every document belongs to a contact. For LHDN e-invoicing, a contact also carries the buyer's TIN and identification number.
| Method | Path | Scope |
|---|---|---|
GET | /contacts | documents:read |
GET | /contacts/{id} | documents:read |
POST | /contacts | contacts:write |
PATCH | /contacts/{id} | contacts:write |
There is no delete endpoint. Contacts can be archived in the app.
The contact object
{
"id": "c0a10000-0000-4000-8000-000000000007",
"tenantId": "7e0a0000-0000-4000-8000-000000000001",
"kind": "customer",
"name": "Aina Rahman",
"companyName": "Teratai Biru Ventures Sdn. Bhd.",
"regNo": "202301012345",
"tin": "C12345678900",
"idType": "BRN",
"idValue": "202301012345",
"sstNo": null,
"msicCode": null,
"email": "aina@teratai-biru.example",
"phone": "+60123456789",
"whatsapp": null,
"billingAddress": {
"line1": "Level 8, Menara Teratai",
"city": "Petaling Jaya",
"postcode": "47301",
"state": "10",
"country": "MYS"
},
"shippingAddress": null,
"notes": null,
"tags": ["corporate"],
"tinValidatedAt": "2026-10-15T02:10:44.000Z",
"tinValid": true,
"defaultPaymentTermsDays": 30,
"archivedAt": null,
"createdAt": "2026-10-15T02:10:44.000Z",
"updatedAt": "2026-10-15T02:10:44.000Z"
}| Field | Type | Description |
|---|---|---|
id | string | Contact ID (UUID). |
kind | string | customer, supplier or both. |
name | string | Person or trading name shown on documents. |
companyName | string or null | Registered company name. |
regNo | string or null | SSM registration number (BRN). |
tin | string or null | LHDN tax identification number, uppercase. |
idType, idValue | string or null | Buyer identification for e-invoices. idType is NRIC, BRN, PASSPORT or ARMY. |
sstNo | string or null | SST registration number. |
msicCode | string or null | 5-digit MSIC code. |
email, phone, whatsapp | string or null | Contact details. email is the default recipient for send. |
billingAddress, shippingAddress | object or null | See Address. |
tags | array of strings | Your labels. |
tinValid, tinValidatedAt | boolean or null, timestamp or null | Result of the TIN check with LHDN, when the check ran. null means not checked. |
defaultPaymentTermsDays | integer or null | Days until due for new invoices to this contact. Invoa uses 30 when empty. |
archivedAt | timestamp or null | Set when the contact is archived. |
Address
| Field | Type | Required | Description |
|---|---|---|---|
line1 | string | Yes | First address line, up to 200 characters. |
line2, line3 | string | No | More address lines. |
city | string | No | City. |
postcode | string | No | Postcode. |
state | string | No | LHDN state code "01" to "17" (for example "10" Selangor, "14" Kuala Lumpur), or free text for foreign addresses. |
country | string | No | ISO 3166-1 alpha-3 code. Default MYS. |
List contacts
GET /api/v1/contactsReturns contacts sorted by name, excluding archived ones. Each item adds outstanding (sen still owed on open invoices) and documentCount.
| Query parameter | Type | Description |
|---|---|---|
search | string | Matches name, company name, email, phone, TIN or registration number. |
tag | string | Only contacts with this tag. |
kind | string | customer, supplier or both. |
includeArchived | boolean | true to include archived contacts. |
limit, offset | integer | See Pagination. |
curl "https://app.invoa.io/api/v1/contacts?search=teratai" \
-H "Authorization: Bearer $INVOA_API_KEY"{
"data": [
{
"id": "c0a10000-0000-4000-8000-000000000007",
"kind": "customer",
"name": "Aina Rahman",
"companyName": "Teratai Biru Ventures Sdn. Bhd.",
"tin": "C12345678900",
"email": "aina@teratai-biru.example",
"tags": ["corporate"],
"outstanding": 135000,
"documentCount": 4
}
],
"pagination": { "total": 1, "limit": 50, "offset": 0, "has_more": false }
}Each item contains every field of the contact object; some are left out above.
Retrieve a contact
GET /api/v1/contacts/{id}Returns the contact with a billing summary and up to 200 of its documents, newest first.
curl https://app.invoa.io/api/v1/contacts/c0a10000-0000-4000-8000-000000000007 \
-H "Authorization: Bearer $INVOA_API_KEY"{
"data": {
"contact": { "id": "c0a10000-0000-4000-8000-000000000007", "name": "Aina Rahman", "companyName": "Teratai Biru Ventures Sdn. Bhd." },
"outstanding": 135000,
"overdue": 0,
"invoicedTotal": 405000,
"paidTotal": 270000,
"documentCount": 4,
"documents": [
{ "id": "d0c00000-0000-4000-8000-000000000042", "type": "invoice", "status": "issued", "number": "INV-26-0042", "total": 135000, "paidAmount": 0 }
]
}
}| Field | Description |
|---|---|
contact | The full contact object. |
outstanding | Sen still owed on issued, sent and partially paid invoices. |
overdue | The part of outstanding that is past its due date. |
invoicedTotal, paidTotal | Totals across this contact's issued invoices (excluding void). |
documentCount | Number of documents returned. |
documents | Document records, without lines. |
Errors: 404 not_found if the contact is not in this company.
Create a contact
POST /api/v1/contacts| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | 1 to 200 characters. |
kind | string | No | customer (default), supplier or both. |
companyName | string | No | Up to 200 characters. |
regNo | string | No | SSM registration number, up to 40 characters. |
tin | string | No | LHDN TIN, for example C12345678900. One or two letters followed by 9 to 12 digits. |
idType | string | No | NRIC, BRN, PASSPORT or ARMY. |
idValue | string | No | The ID number for idType, up to 40 characters. |
sstNo | string | No | Up to 40 characters. |
msicCode | string | No | 5-digit MSIC code. |
email | string | No | Valid email address. |
phone, whatsapp | string | No | 7 to 20 characters: digits, spaces, +, (, ), -. |
billingAddress, shippingAddress | object | No | See Address. |
notes | string | No | Up to 5,000 characters. |
tags | array of strings | No | Up to 20 tags, each up to 40 characters. |
defaultPaymentTermsDays | integer | No | 0 to 365. |
priceListId | string or null | No | The customer's price list; null for standard prices. An unknown or archived list returns 404. |
When you send a tin, Invoa checks it with LHDN if the check is available and stores the result in tinValid. A failed check does not block saving. See Find a customer's TIN.
curl https://app.invoa.io/api/v1/contacts \
-H "Authorization: Bearer $INVOA_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "Aina Rahman",
"companyName": "Teratai Biru Ventures Sdn. Bhd.",
"regNo": "202301012345",
"tin": "C12345678900",
"idType": "BRN",
"idValue": "202301012345",
"email": "aina@teratai-biru.example",
"phone": "+60123456789",
"billingAddress": { "line1": "Level 8, Menara Teratai", "city": "Petaling Jaya", "postcode": "47301", "state": "10" },
"defaultPaymentTermsDays": 30
}'Returns 201 Created with { "data": <contact object> }.
Errors: 400 validation with details for invalid fields, for example a malformed TIN or email.
Update a contact
PATCH /api/v1/contacts/{id}Send only the fields to change, using the same fields as create. Fields you leave out keep their current values; defaults such as kind customer apply only when creating. Send null to clear an optional field, and send tags in full to replace the list. When tin, idType or idValue change, the TIN is checked with LHDN again.
curl -X PATCH https://app.invoa.io/api/v1/contacts/c0a10000-0000-4000-8000-000000000007 \
-H "Authorization: Bearer $INVOA_API_KEY" \
-H "content-type: application/json" \
-d '{ "email": "accounts@teratai-biru.example" }'Returns 200 OK with { "data": <contact object> }.
Errors: 400 validation, 404 not_found.
Related
Something unclear or out of date? Tell us at hello@invoa.io and we'll fix the page.