curl --request GET \
--url https://sandbox-api.sakawave.example/v1/customers \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://sandbox-api.sakawave.example/v1/customers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox-api.sakawave.example/v1/customers"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"items": [
{
"id": "01K2Z3AB4C5D6E7F8G9HJKMNPQ",
"type": "individual",
"jurisdiction": "NG",
"externalReference": "cust_1001",
"displayName": "Ada Okafor",
"name": null,
"firstName": "Ada",
"middleName": null,
"lastName": "Okafor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"dateOfBirth": "1992-04-18",
"gender": "female",
"address": {
"line1": "14 Marina Road",
"line2": null,
"city": "Lagos",
"state": "Lagos",
"postalCode": "100001",
"country": "NG"
},
"tier": 1,
"hasBvn": true,
"hasNin": false,
"hasPassport": false,
"hasDriversLicence": false,
"hasTaxId": false,
"hasRegistrationNumber": false,
"createdAt": "2026-08-14T09:00:00.000Z",
"updatedAt": "2026-08-14T09:00:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 1,
"pageCount": 1,
"hasNext": false,
"hasPrevious": false
}
}{
"statusCode": 400,
"message": "Must be a valid identifier.",
"code": "validation_failed",
"errors": [
{
"message": "Must be a valid identifier.",
"field": "accountId",
"code": "custom",
"path": [
"accountId"
]
}
]
}{
"statusCode": 401,
"code": "INVALID_API_KEY",
"message": "Invalid or inactive API credentials."
}{
"statusCode": 404,
"code": "resource_not_found",
"message": "Resource not found."
}{
"statusCode": 409,
"code": "resource_conflict",
"message": "The request conflicts with the current resource state."
}{
"statusCode": 429,
"message": "Too many API requests. Try again later.",
"code": "api_key_rate_limit_exceeded",
"retryAfterSeconds": 17
}{
"statusCode": 500,
"code": "internal_server_error",
"message": "An unexpected error occurred."
}List customers
Returns customers belonging to the authenticated business, newest first. Archived customers are never included. An unknown filter or sort key is rejected by name rather than ignored, so a typo cannot silently widen a result set.
curl --request GET \
--url https://sandbox-api.sakawave.example/v1/customers \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://sandbox-api.sakawave.example/v1/customers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox-api.sakawave.example/v1/customers"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"items": [
{
"id": "01K2Z3AB4C5D6E7F8G9HJKMNPQ",
"type": "individual",
"jurisdiction": "NG",
"externalReference": "cust_1001",
"displayName": "Ada Okafor",
"name": null,
"firstName": "Ada",
"middleName": null,
"lastName": "Okafor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"dateOfBirth": "1992-04-18",
"gender": "female",
"address": {
"line1": "14 Marina Road",
"line2": null,
"city": "Lagos",
"state": "Lagos",
"postalCode": "100001",
"country": "NG"
},
"tier": 1,
"hasBvn": true,
"hasNin": false,
"hasPassport": false,
"hasDriversLicence": false,
"hasTaxId": false,
"hasRegistrationNumber": false,
"createdAt": "2026-08-14T09:00:00.000Z",
"updatedAt": "2026-08-14T09:00:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 25,
"total": 1,
"pageCount": 1,
"hasNext": false,
"hasPrevious": false
}
}{
"statusCode": 400,
"message": "Must be a valid identifier.",
"code": "validation_failed",
"errors": [
{
"message": "Must be a valid identifier.",
"field": "accountId",
"code": "custom",
"path": [
"accountId"
]
}
]
}{
"statusCode": 401,
"code": "INVALID_API_KEY",
"message": "Invalid or inactive API credentials."
}{
"statusCode": 404,
"code": "resource_not_found",
"message": "Resource not found."
}{
"statusCode": 409,
"code": "resource_conflict",
"message": "The request conflicts with the current resource state."
}{
"statusCode": 429,
"message": "Too many API requests. Try again later.",
"code": "api_key_rate_limit_exceeded",
"retryAfterSeconds": 17
}{
"statusCode": 500,
"code": "internal_server_error",
"message": "An unexpected error occurred."
}Filtering
Filters are written asfield=value, or field:operator=value where the field supports more than equality. A repeated parameter and a comma-separated one mean the same thing, so type:in=individual&type:in=business and type:in=individual,business are equivalent.
GET /v1/customers?type=individual&tier:gte=1&createdAt:gte=2026-08-01T00:00:00Z&sort=-createdAt&pageSize=50
errors array, so three bad filters are reported at once rather than one request at a time.
Error codes
| Status | code | Cause |
|---|---|---|
400 | validation_failed | An unknown filter or sort key, an unsupported operator, a page below 1, or a page size above 100. |
401 | INVALID_API_KEY | The key is missing, invalid, inactive, expired, from the other environment, or blocked by its IP allowlist. |
404 | client_not_found | The key authenticated, but its business no longer exists. |
409 | client_not_a_business | Customer management is available only to business clients. |
429 | api_key_rate_limit_exceeded | The per-minute limit for this key was exceeded. |
Authorizations
A secret API key, sent as Authorization: Bearer sk_test_… in sandbox or Bearer sk_live_… in live.
Query Parameters
One-based page number.
x >= 1Records per page. A larger value is rejected rather than capped, so your paging arithmetic stays correct.
1 <= x <= 100Case-insensitive term matched against name, firstName, lastName, email, and externalReference. Maximum 100 characters.
100Up to three comma-separated keys from name, firstName, lastName, tier, and createdAt. Prefix a key with - for descending order.
Exact match on the stored name.
Exact match. Individual customers only.
Exact match. Individual customers only.
Exact match on the stored, lowercased address.
Exact match on your own reference.
Filter by customer type.
individual, business Comma-separated customer types.
ISO 3166-1 alpha-2 country of the customer relationship.
2Comma-separated country codes. At most 50.
Exact tier. Customers are created at tier 1.
1 <= x <= 3Tier at or above this value.
1 <= x <= 3Tier at or below this value.
1 <= x <= 3Created at or after this ISO 8601 timestamp.
Created at or before this ISO 8601 timestamp.