Docs / API reference

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.

MethodPathScope
GET/contactsdocuments:read
GET/contacts/{id}documents:read
POST/contactscontacts:write
PATCH/contacts/{id}contacts:write

There is no delete endpoint. Contacts can be archived in the app.

The contact object

json
{
  "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"
}
FieldTypeDescription
idstringContact ID (UUID).
kindstringcustomer, supplier or both.
namestringPerson or trading name shown on documents.
companyNamestring or nullRegistered company name.
regNostring or nullSSM registration number (BRN).
tinstring or nullLHDN tax identification number, uppercase.
idType, idValuestring or nullBuyer identification for e-invoices. idType is NRIC, BRN, PASSPORT or ARMY.
sstNostring or nullSST registration number.
msicCodestring or null5-digit MSIC code.
email, phone, whatsappstring or nullContact details. email is the default recipient for send.
billingAddress, shippingAddressobject or nullSee Address.
tagsarray of stringsYour labels.
tinValid, tinValidatedAtboolean or null, timestamp or nullResult of the TIN check with LHDN, when the check ran. null means not checked.
defaultPaymentTermsDaysinteger or nullDays until due for new invoices to this contact. Invoa uses 30 when empty.
archivedAttimestamp or nullSet when the contact is archived.

Address

FieldTypeRequiredDescription
line1stringYesFirst address line, up to 200 characters.
line2, line3stringNoMore address lines.
citystringNoCity.
postcodestringNoPostcode.
statestringNoLHDN state code "01" to "17" (for example "10" Selangor, "14" Kuala Lumpur), or free text for foreign addresses.
countrystringNoISO 3166-1 alpha-3 code. Default MYS.

List contacts

http
GET /api/v1/contacts

Returns contacts sorted by name, excluding archived ones. Each item adds outstanding (sen still owed on open invoices) and documentCount.

Query parameterTypeDescription
searchstringMatches name, company name, email, phone, TIN or registration number.
tagstringOnly contacts with this tag.
kindstringcustomer, supplier or both.
includeArchivedbooleantrue to include archived contacts.
limit, offsetintegerSee Pagination.
bash
curl "https://app.invoa.io/api/v1/contacts?search=teratai" \
  -H "Authorization: Bearer $INVOA_API_KEY"
json
{
  "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

http
GET /api/v1/contacts/{id}

Returns the contact with a billing summary and up to 200 of its documents, newest first.

bash
curl https://app.invoa.io/api/v1/contacts/c0a10000-0000-4000-8000-000000000007 \
  -H "Authorization: Bearer $INVOA_API_KEY"
json
{
  "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 }
    ]
  }
}
FieldDescription
contactThe full contact object.
outstandingSen still owed on issued, sent and partially paid invoices.
overdueThe part of outstanding that is past its due date.
invoicedTotal, paidTotalTotals across this contact's issued invoices (excluding void).
documentCountNumber of documents returned.
documentsDocument records, without lines.

Errors: 404 not_found if the contact is not in this company.

Create a contact

http
POST /api/v1/contacts
FieldTypeRequiredDescription
namestringYes1 to 200 characters.
kindstringNocustomer (default), supplier or both.
companyNamestringNoUp to 200 characters.
regNostringNoSSM registration number, up to 40 characters.
tinstringNoLHDN TIN, for example C12345678900. One or two letters followed by 9 to 12 digits.
idTypestringNoNRIC, BRN, PASSPORT or ARMY.
idValuestringNoThe ID number for idType, up to 40 characters.
sstNostringNoUp to 40 characters.
msicCodestringNo5-digit MSIC code.
emailstringNoValid email address.
phone, whatsappstringNo7 to 20 characters: digits, spaces, +, (, ), -.
billingAddress, shippingAddressobjectNoSee Address.
notesstringNoUp to 5,000 characters.
tagsarray of stringsNoUp to 20 tags, each up to 40 characters.
defaultPaymentTermsDaysintegerNo0 to 365.
priceListIdstring or nullNoThe 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.

bash
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

http
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.

bash
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.

Something unclear or out of date? Tell us at hello@invoa.io and we'll fix the page.