Managing Customers
Create, update, find, and read back the customers you issue e-invoices to.
Every e-invoice references its buyer by customerId rather than carrying their details inline. This guide covers the customer records behind that id: how creating one doubles as updating it, how to find one again, and how to read it back.
Customers are scoped to your business and to the mode you created them in, so a test id will not resolve in live. Create your customers again when you go live rather than carrying ids across.
Creating or updating a customer
Issuing an E-Invoice walks through the create request, its required fields, and the response. Keep the id it returns: that is the customerId you send on every invoice for this customer.
There is no separate update endpoint. Create a customer checks the tin first, then matches on the email, so what happens when you post a customer depends on what already exists:
| You send | Result |
|---|---|
A tin that any existing customer already has | The request fails with a 409, nothing changes |
| An email you have not used before | A new customer is created |
An existing email, with a tin no customer has yet | The existing customer is updated in place |
A tin belongs to one customer per business and mode, and the check applies whatever the email, so posting the same customer twice with its tin also returns 409 A customer with TIN 87654321-0001 already exists for this business. Duplo trims the tin and upper-cases it before comparing and storing it, so 87654321-0001 and 87654321-0001 count as the same TIN.
Neither the 409 nor the update returns a new id, so store the id from the first response and reuse it rather than creating the customer again.
Finding a customer
If you did not keep the id, the List customers endpoint pages through your invoice customers, newest first by default:
curl --request GET \
--url 'https://spend-api.tryduplo.com/api/v1/customers?page=1&limit=20&searchTerm=buyer' \
--header 'Authorization: Bearer <your-api-key>'Every parameter is optional:
| Parameter | Accepts | Notes |
|---|---|---|
page | A number, for example 1 | Which page to return |
limit | A number, for example 20 | How many customers per page, 20 if omitted |
searchTerm | Letters, digits, spaces, and +, _, ', ", &, - | Matches part of the name, email, phone, TIN, or reference, ignoring case |
sort | A field name, -field for descending, as in -createdAt | Comma-separate several |
searchTerm does not accept @ or ., so search on part of an email address, such as buyer, rather than the whole of it.
The page of customers and its meta sit together inside data:
{
"statusCode": 200,
"timestamp": "2024-01-23T10:04:15.902Z",
"path": "/api/v1/customers?page=1&limit=20&searchTerm=buyer",
"message": "Customers retrieved successfully",
"data": {
"data": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"businessId": "f3f3c6a1-45e3-44aa-b05a-1fbe98d52d09",
"reference": "cust_invoice_A1B2C3D4E5F6",
"modules": ["invoice"],
"firstName": "Example Buyer",
"lastName": "Limited",
"email": "ap@buyer.example",
"phone": "+2348098765432",
"tin": "87654321-0001",
"country": "NG",
"state": "FCT",
"city": "Abuja",
"address": "2 Buyer Avenue",
"postcode": "900001",
"createdAt": "2024-01-23T09:58:11.187Z",
"updatedAt": "2024-01-23T09:58:11.187Z"
}
],
"meta": {
"total": 1,
"page": 1,
"limit": 20,
"count": 1,
"previousPage": false,
"nextPage": false,
"pageCount": 1,
"totalRecords": 1
}
}
}Storing the id against your own record at creation is still cheaper than searching for it on every invoice.
Reading a customer back
To read one customer, call Get customer with the id you stored at creation:
curl --request GET \
--url https://spend-api.tryduplo.com/api/v1/customers/123e4567-e89b-12d3-a456-426614174000 \
--header 'Authorization: Bearer <your-api-key>'{
"statusCode": 200,
"timestamp": "2024-01-23T10:05:47.331Z",
"path": "/api/v1/customers/123e4567-e89b-12d3-a456-426614174000",
"message": "Customer retrieved successfully",
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"businessId": "f3f3c6a1-45e3-44aa-b05a-1fbe98d52d09",
"reference": "cust_invoice_A1B2C3D4E5F6",
"modules": ["invoice"],
"firstName": "Example Buyer",
"lastName": "Limited",
"email": "ap@buyer.example",
"phone": "+2348098765432",
"tin": "87654321-0001",
"country": "NG",
"state": "FCT",
"city": "Abuja",
"address": "2 Buyer Avenue",
"postcode": "900001",
"createdAt": "2024-01-23T09:58:11.187Z",
"updatedAt": "2024-01-23T09:58:11.187Z"
}
}The response carries the stored customer details, including the tin and postcode that invoice validation depends on. That makes this the first call to reach for when an invoice fails validation on customer data: the invoice payload does not carry the customer inline, so a missing TIN surfaces as an invoice error whose actual cause is sitting in the customer record.
How is this guide?
Last updated on