Customers
The Customers API allows you to manage your customer records. When a customer email is provided with a Quick Pay request, the API automatically creates or updates the customer record. You can also import, list, search, and soft-delete customers independently.
List customers
Returns a paginated list of customers. Supports searching by name or email, sorting, and date range filtering. Default pagination is 25 results per page (max 1000).
Request
GET /v2/customers
Query parameters
| Parameter | Type | Description |
|---|---|---|
search | string | Filter by name or email. |
sort | string | Sort order. One of: created_asc, created_desc, first_name_asc, first_name_desc, last_name_asc, last_name_desc, last_order_asc, last_order_desc. |
start_date | string | Start date (Y-m-d). |
end_date | string | End date (Y-m-d). |
per_page | integer | Results per page (default 25, max 1000). |
Response
{
"data": [
{
"id": "1d368e62",
"first_name": "John",
"last_name": "Testmore",
"full_name": "John Testmore",
"email": "[email protected]",
"address": "1 Test Street, Test Town",
"address_formatted": {
"address_line_1": "1 Test Street",
"address_line_2": null,
"town": "Test Town",
"postcode": null
},
"telephone": "0123456789",
"marketing_consented_at": null,
"created_at": "2023-05-02T22:07:21.000000Z",
"updated_at": "2023-05-02T22:07:21.000000Z"
}
],
"links": {
"first": "https://api.wonderful.one/v2/customers?page=1",
"last": null,
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"path": "https://api.wonderful.one/v2/customers",
"per_page": 25,
"to": 1
}
}
Example
curl --request GET \
--get "https://api.wonderful.one/v2/customers?search=john&sort=last_name_asc&per_page=10" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL("https://api.wonderful.one/v2/customers");
const params = { search: "john", sort: "last_name_asc", per_page: "10" };
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
fetch(url, {
headers: {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
},
})
.then(response => response.json())
.then(data => console.log(data.data));
$client = new \GuzzleHttp\Client();
$url = 'https://api.wonderful.one/v2/customers';
$response = $client->get($url, [
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'search' => 'john',
'sort' => 'last_name_asc',
'per_page' => 10,
],
]);
$body = json_decode((string) $response->getBody());
print_r($body->data);
Create a customer
Inserts a new customer record. The email address is the unique identifier — creating a customer with an existing email updates the record instead of duplicating it.
Request
POST /v2/customers
Content-Type: application/json
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
first_name | string | no | Max 255 characters. |
last_name | string | no | Max 255 characters. |
email | string | yes | Valid email address. Max 255 characters. |
telephone | string | no | Phone number. |
marketing_consent | boolean | no | true if the customer opted in to marketing. |
address | string or object | no | Either a single string (e.g. "123 Some Street, London, SW1A 1AA") or an object with address_line_1, address_line_2, town, postcode. When using an object, address_line_1 and postcode are required. |
Response
{
"data": {
"id": "1d368e62",
"first_name": "John",
"last_name": "Smith",
"full_name": "John Smith",
"email": "[email protected]",
"address": "123 Some Street, London, SW1A 1AA",
"address_formatted": {
"address_line_1": "123 Some Street",
"address_line_2": null,
"town": "London",
"postcode": "SW1A 1AA"
},
"telephone": "0123456789",
"marketing_consented_at": null,
"created_at": "2024-03-05T11:50:43.000000Z",
"updated_at": "2024-03-05T11:50:43.000000Z"
}
}
Example
curl --request POST \
"https://api.wonderful.one/v2/customers" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{
"first_name": "John",
"last_name": "Smith",
"email": "[email protected]",
"telephone": "01234 567890",
"marketing_consent": true,
"address": {
"address_line_1": "123 Some Street",
"town": "London",
"postcode": "SW1A 1AA"
}
}'
fetch("https://api.wonderful.one/v2/customers", {
method: "POST",
headers: {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
},
body: JSON.stringify({
first_name: "John",
last_name: "Smith",
email: "[email protected]",
telephone: "01234 567890",
marketing_consent: true,
address: {
address_line_1: "123 Some Street",
town: "London",
postcode: "SW1A 1AA",
},
}),
})
.then(response => response.json())
.then(data => console.log(data.data));
$client = new \GuzzleHttp\Client();
$response = $client->post('https://api.wonderful.one/v2/customers', [
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'first_name' => 'John',
'last_name' => 'Smith',
'email' => '[email protected]',
'telephone' => '01234 567890',
'marketing_consent' => true,
'address' => [
'address_line_1' => '123 Some Street',
'town' => 'London',
'postcode' => 'SW1A 1AA',
],
],
]);
$body = json_decode((string) $response->getBody());
print_r($body->data);
Get a customer
Request
GET /v2/customers/{id}
Example
curl --request GET \
--get "https://api.wonderful.one/v2/customers/1d368e62" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
fetch("https://api.wonderful.one/v2/customers/1d368e62", {
headers: {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
},
})
.then(response => response.json())
.then(data => console.log(data.data));
$client = new \GuzzleHttp\Client();
$response = $client->get('https://api.wonderful.one/v2/customers/1d368e62', [
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]);
$body = json_decode((string) $response->getBody());
print_r($body->data);
Update a customer
This is a full replacement — include all fields you want to keep, even if unchanged.
Request
PUT /v2/customers/{id}
Example
curl --request PUT \
"https://api.wonderful.one/v2/customers/1d368e62" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{
"first_name": "Jonathan",
"last_name": "Smith",
"email": "[email protected]",
"telephone": "01234 567890"
}'
fetch("https://api.wonderful.one/v2/customers/1d368e62", {
method: "PUT",
headers: {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
},
body: JSON.stringify({
first_name: "Jonathan",
last_name: "Smith",
email: "[email protected]",
telephone: "01234 567890",
}),
})
.then(response => response.json())
.then(data => console.log(data.data));
$client = new \GuzzleHttp\Client();
$response = $client->put('https://api.wonderful.one/v2/customers/1d368e62', [
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'first_name' => 'Jonathan',
'last_name' => 'Smith',
'email' => '[email protected]',
'telephone' => '01234 567890',
],
]);
$body = json_decode((string) $response->getBody());
print_r($body->data);
Delete a customer
Soft-deletes the customer record. A successful delete returns 204 No Content. Attempting to delete an already-deleted record returns 404. Customers with existing orders cannot be deleted.
Request
DELETE /v2/customers/{id}
Example
curl --request DELETE \
"https://api.wonderful.one/v2/customers/1d368e62" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
fetch("https://api.wonderful.one/v2/customers/1d368e62", {
method: "DELETE",
headers: {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
},
});
$client = new \GuzzleHttp\Client();
$response = $client->delete('https://api.wonderful.one/v2/customers/1d368e62', [
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]);
Marketing consent
The marketing_consented_at field indicates when a customer last opted in to marketing. A null value means they have not consented. Use this to segment your email lists:
marketing_consented_atis a date: the customer opted in — safe to send newsletters and promotional emails.marketing_consented_atisnull: do not send marketing emails. Transactional messages (order confirmations, account updates) are still permissible.
Next steps
- Orders & refunds — see how customer records are linked to orders.
- Webhooks — receive real-time payment notifications.