Customers endpoints
The customers endpoints cover reading and writing customer records over the API: list (with filters and search), fetch a single customer, create a new one, and update fields on an existing one.
Customers are the accounts that log in to your storefront and place orders. See Customers for the underlying data model.
GET /api/v1/customers
List customers in your company.
Required scope: customers:read
Query parameters
| Param | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Page size, capped at 100. See Pagination. |
cursor | string | — | Pagination cursor from a previous response. |
status | ACTIVE / BLOCKED | — | Filter by customer status. |
search | string | — | Case-insensitive substring match on email and name. |
Example
curl "https://distribu.app/api/v1/customers?status=ACTIVE&limit=50" \
-H "Authorization: Bearer dk_..."
Response
{
"data": [
{
"id": "clxxcustomer1...",
"email": "buyer@acme.com",
"name": "Acme Restaurant Group",
"status": "ACTIVE",
"notes": "Weekly delivery, dock B.",
"creditLimit": 5000,
"taxRateOverride": 0.08,
"emailVerified": true,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-04-10T09:30:00.000Z"
}
],
"pagination": {
"hasMore": false,
"nextCursor": null
}
}
Sorted by createdAt descending.
Notes on fields
name— Nullable. Some customers register with only an email.notes— Nullable. Your internal notes; never shown to the customer.creditLimit— Nullable decimal. For your records — Distribu doesn't enforce it at order placement.taxRateOverride— Nullable decimal fraction between0and0.3. When set, overrides the company-wide tax rate for this customer.nullmeans "use the company default."emailVerified—truefor customers who completed email verification (self-registered or invited contacts). CSV-imported customers startfalseuntil they complete a password reset.- Password — Not returned, ever.
- Shipping addresses — Not returned by this endpoint. Use the dashboard or the storefront APIs for per-address detail.
GET /api/v1/customers/{id}
Fetch a single customer by ID.
Required scope: customers:read
Example
curl https://distribu.app/api/v1/customers/clxxcustomer1... \
-H "Authorization: Bearer dk_..."
Response
{
"data": {
"id": "clxxcustomer1...",
"email": "buyer@acme.com",
"name": "Acme Restaurant Group",
"status": "ACTIVE",
"notes": "Weekly delivery, dock B.",
"creditLimit": 5000,
"taxRateOverride": 0.08,
"emailVerified": true,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-04-10T09:30:00.000Z"
}
}
Errors
404—Customer not found.— No customer with that ID in your company.
POST /api/v1/customers
Create a new customer.
Required scope: customers:write
Request body
{
"email": "buyer@acme.com",
"name": "Acme Restaurant Group",
"notes": "Weekly delivery, dock B.",
"creditLimit": 5000,
"taxRateOverride": 0.08,
"status": "ACTIVE"
}
| Field | Type | Required | Notes |
|---|---|---|---|
email | string | yes | Must be unique within your company. |
name | string | null | no | 1–200 chars when set. |
notes | string | null | no | 0–2000 chars. |
creditLimit | number | null | no | 0–100,000,000. |
taxRateOverride | number | null | no | Fraction 0–0.3 (e.g., 0.08 = 8%). |
status | string | no | ACTIVE (default) or BLOCKED. |
Example
curl -X POST https://distribu.app/api/v1/customers \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{
"email": "buyer@acme.com",
"name": "Acme Restaurant Group",
"creditLimit": 5000
}'
Response
201 Created with the new customer.
{
"data": {
"id": "clxxcustomer1...",
"email": "buyer@acme.com",
"name": "Acme Restaurant Group",
"status": "ACTIVE",
"notes": null,
"creditLimit": 5000,
"taxRateOverride": null,
"emailVerified": false,
"createdAt": "2026-04-17T14:22:00.000Z",
"updatedAt": "2026-04-17T14:22:00.000Z"
}
}
API-created customers:
- Start with no password — they can't log in to the storefront
until they reset one. Send them the password-reset URL for your
store (
/store/{slug}/reset) so they can set one themselves. - Start with
emailVerified: false— verified once they complete the reset flow. - Are identical in every other way to a customer who registered themselves.
Errors
| Status | Message |
|---|---|
400 | Invalid JSON body. |
400 | Email is required. |
400 | Invalid email address. |
400 | Credit limit must be between 0 and 100000000. |
400 | Tax rate override must be between 0 and 0.3. |
409 | A customer with this email already exists. |
PATCH /api/v1/customers/{id}
Update fields on an existing customer.
Required scope: customers:write
Request body
Every field is optional — send only what you want to change.
{
"name": "Acme Restaurant Group (Downtown)",
"notes": "Weekly delivery, dock B. Ring for access.",
"creditLimit": 7500,
"taxRateOverride": null,
"status": "ACTIVE"
}
| Field | Type | Notes |
|---|---|---|
name | string | null | Set to null to clear. |
notes | string | null | Set to null to clear. |
creditLimit | number | null | Set to null to clear. |
taxRateOverride | number | null | Set to null to use the company default. |
status | string | ACTIVE or BLOCKED. Blocked customers can't log in. |
email is immutable over the API — changing a customer's email
address isn't supported today. Ask them to use a new account, or do
it from the dashboard.
Example
# Block a customer
curl -X PATCH https://distribu.app/api/v1/customers/clxxcustomer1... \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{ "status": "BLOCKED" }'
Response
The full updated customer, same shape as GET /api/v1/customers/{id}.
Errors
| Status | Message |
|---|---|
400 | Invalid JSON body. |
400 | Credit limit must be between 0 and 100000000. |
400 | Tax rate override must be between 0 and 0.3. |
400 | Invalid status. |
404 | Customer not found. |
What's not here (yet)
DELETE /api/v1/customers/{id}— Not exposed. Block instead (PATCH { status: "BLOCKED" }). Deleting a customer would cascade over their order history, which is usually not what you want.- Customer contacts — the sub-users on a customer account (see Customer contacts) aren't reachable over the API yet.
- Shipping addresses — not exposed.
- Price overrides — not exposed over the API; manage from the dashboard.
Next: Webhooks endpoints.
