API
Customers API
Create, upsert, list, retrieve and update customers, keyed by your own externalReference.
On this page
Overview#
Customers are the people and businesses you invoice and take payments from. Keep them in sync with your own system by sending your ID as externalReference: creating with the same reference again updates the existing customer instead of duplicating it. Available on every plan that includes the REST API.
| Endpoint | Purpose |
|---|---|
POST /api/v1/customers | Create, or upsert by externalReference |
GET /api/v1/customers | List, filter by externalReference or email |
GET /api/v1/customers/{id} | Get one customer |
PATCH /api/v1/customers/{id} | Update fields |
The customer object#
{
"id": "cmg2c0s7t0003cust0001abcd",
"accountCode": "CUS-00042",
"externalReference": "CRM-1001",
"email": "[email protected]",
"firstName": "Thandi",
"lastName": "Nkosi",
"company": "Nkosi Trading (Pty) Ltd",
"vatNumber": "4123456789",
"phone": "+27821234567",
"address": "12 Long Street, Cape Town, 8001",
"active": true,
"metadata": {
"crmId": "0061x00000AbCdE"
},
"createdAt": "2026-09-25T08:00:00.000Z",
"updatedAt": "2026-09-25T08:00:00.000Z"
}| Field | Type | Description |
|---|---|---|
idrequired | string | CentraPoint customer ID. |
accountCoderequired | string | Account code assigned by CentraPoint (shown on invoices and in accounting exports). |
externalReferencerequired | string | null | Your ID for the customer. |
emailrequired | string | Stored in lower case. |
firstNamerequired | string | |
lastName, company, vatNumber, phone, addressrequired | string | null | Optional details, printed on invoices where relevant. |
activerequired | boolean | Inactive customers are kept for history. |
metadatarequired | object | Your key/value data; {} when empty. See metadata. |
createdAt, updatedAtrequired | string | ISO 8601 UTC timestamps. |
Create or upsert a customer#
/api/v1/customers| Field | Type | Description |
|---|---|---|
externalReferenceoptional | string | 1–190 characters. Your ID; makes the request an upsert. |
emailrequired | string (email) | Up to 200 characters. |
firstNamerequired | string | 1–100 characters. |
lastNameoptional | string | null | Up to 100 characters. |
companyoptional | string | null | Up to 200 characters. |
vatNumberoptional | string | null | Up to 30 characters. |
phoneoptional | string | null | Up to 30 characters. |
addressoptional | string | null | Up to 1000 characters. |
metadataoptional | object | Key/value data (rules). |
curl -X POST "https://app.centrapoint.co.za/api/v1/customers" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
-H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31" \
-H "Content-Type: application/json" \
-d '{
"externalReference": "CRM-1001",
"email": "[email protected]",
"firstName": "Thandi",
"lastName": "Nkosi",
"company": "Nkosi Trading (Pty) Ltd",
"vatNumber": "4123456789",
"phone": "+27821234567",
"metadata": {
"crmId": "0061x00000AbCdE"
}
}'Returns the customer object. Supports the Idempotency-Key header.
Upsert rules#
| Request | Situation | Result |
|---|---|---|
| No externalReference | – | 201 new customer (even if the email already exists) |
| With externalReference | A customer has this reference | 200 that customer updated with the sent fields |
| With externalReference | No match, but a customer with the same email has no reference | 200 that customer is adopted: the reference is set and fields updated |
| With externalReference | No match | 201 new customer |
On update, fields you omit keep their values. Concurrent upserts with the same reference are serialised, so they never create two customers. Creating a customer counts towards your plan's customer limit (403 plan_limit).
List customers#
/api/v1/customers| Field | Type | Description |
|---|---|---|
externalReferenceoptional | string | Exact match. |
emailoptional | string | Exact match, case-insensitive. |
limitoptional | integer | 1–100, default 20. |
Returns { "data": [ … ] }, newest first.
curl -X GET "https://app.centrapoint.co.za/api/v1/customers?externalReference=CRM-1001" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY"Get a customer#
/api/v1/customers/{id}curl -X GET "https://app.centrapoint.co.za/api/v1/customers/cmg2c0s7t0003cust0001abcd" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY"Update a customer#
/api/v1/customers/{id}Partial update: send only the fields to change. null clears an optional field. metadata replaces the whole map (send null to clear it). active: false deactivates the customer. You can also set or change externalReference (it must not belong to another customer). Unknown fields are rejected with 400. The Idempotency-Key header is not used on PATCH, which is safe to repeat.
curl -X PATCH "https://app.centrapoint.co.za/api/v1/customers/cmg2c0s7t0003cust0001abcd" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+27829876543",
"company": null
}'Errors#
| Status | error | When |
|---|---|---|
| 400 | invalid_request | Validation failed, invalid metadata, unknown field (PATCH), or externalReference already used by another customer (PATCH). |
| 401 | unauthorized | Missing or invalid API key. |
| 403 | plan_restricted / plan_limit / account_restricted | No API access, customer limit reached, or account read-only (writes). |
| 404 | not_found | No customer with this ID in your organisation. |
| 409 | idempotency_conflict | Idempotency-Key reused with a different body (POST). |
| 429 / 500 | rate_limited / internal_error | See Errors |