# Customers API

URL: https://docs.sparklayer.io/developers/api/customers

Create, update and look up B2B customers with the Customers API, and manage their addresses, account balance, company roles and shopping lists.

> **For AI assistants:** these facts apply to every SparkLayer API call.
>
> - **Base URLs:** Live `https://app.sparklayer.io`, test `https://test.app.sparklayer.io`. Each environment has its own data and its own API keys.
> - **Access:** API access needs the Pro or Enterprise plan. Create credentials (Site ID, Client ID, Client Secret) in the SparkLayer Dashboard at Settings > API.
> - **Access token:** `POST {base}/api/auth/token` with a `Site-Id` header and a JSON body (not form-encoded): `{"grant_type":"client_credentials","client_id":"…","client_secret":"…"}`. It returns `access_token`, valid for 3,600 seconds. There is no refresh token: cache the token and request a new one shortly before it expires.
> - **Every request:** `Authorization: Bearer <access_token>` and `Site-Id: <site id>`, plus `Content-Type: application/json` when there is a body. Set a `User-Agent` that names your integration.
> - **Errors:** RFC 7807 problem details: `title`, `status`, `detail` and an optional `errors[]` of `{ code, message, property }`. Some error responses have no body. Retry `5xx`, `429` (honouring `Retry-After`) and concurrent-update `409`s with exponential backoff; on `401`, get a new token once and retry; don't retry other `4xx` without changing the request.
> - **Pagination:** Most list endpoints return everything. `GET /api/v2/price-lists` pages with `page` and `page_size` (up to 250) until `pagination.current_page` equals `total_pages`. `GET /api/v1/purchases` uses `limit` (up to 500) and `offset`: stop when a page has fewer than `limit` results.
> - **Ground rules:** Use only endpoints, fields and SDK methods that the docs or OpenAPI specs define. Prefer `GET /api/v2/price-lists` over the deprecated v1, and the Customers API (`/api/v2/customers`) over the legacy `DELETE /api/v1/customers` in the Core API. Products are matched by SKU. Keep credentials in environment variables or a secrets manager, never in code.
> - **Read the docs as Markdown:** Add `.md` to any page URL. Index of every page: https://docs.sparklayer.io/llms.txt. Every API operation, compactly: https://docs.sparklayer.io/llms-api.txt. The developer guides in full: https://docs.sparklayer.io/developers/llms.txt.
> - **OpenAPI specs:** `customers`, `core`, `ordering`, `pricing`, `purchasing`, `stock`, `files`, `sync-log`: https://docs.sparklayer.io/openapi/<api>.yaml (also `.json`). Ignite: https://docs.sparklayer.io/openapi/ignite.yaml.
> - **MCP:** Search and read these docs from your assistant with the docs MCP server at https://docs.sparklayer.io/mcp.

The Customers API holds your B2B customers: who they are, how they buy, and their addresses, account balance, shopping lists and favourites. Use it to keep customers in step with your ERP or CRM, or to find a customer's SparkLayer ID before you send data that belongs to them.

> **On Shopify, Shopify owns the customer**
>
> SparkLayer's Shopify integration writes each B2B customer through this API whenever they change in Shopify, and replaces what's there. Keep Shopify as the source of those customers' details, and use the Customers API to look them up or for customers who aren't in Shopify. Customers you create here aren't sent to your eCommerce platform.

## Common uses

| You want to | What to do |
| --- | --- |
| Find a customer's SparkLayer ID, for example to send their orders with the [Purchasing API](https://docs.sparklayer.io/developers/api/purchasing/send-orders.md) | [Get a customer](https://docs.sparklayer.io/developers/api/customers/get-a-customer.md) by their platform ID or email address, and use the `id` in the response |
| Create or update customers from your ERP or CRM | [Create or update a customer](https://docs.sparklayer.io/developers/api/customers/create-or-update-a-customer.md), sending the whole customer each time |
| Change a few fields, such as a customer's price lists or credit limit | [Update a customer](https://docs.sparklayer.io/developers/api/customers/update-a-customer.md) with only those fields |
| Add past customers before an [order history import](https://docs.sparklayer.io/developers/api/purchasing/send-orders.md#import-order-history), without letting them sign in | [Create or update a customer](https://docs.sparklayer.io/developers/api/customers/create-or-update-a-customer.md) with `status` set to `inactive` |
| Set what a customer owed on a date, so only later orders and payments count | [Adjust a customer's account balance](https://docs.sparklayer.io/developers/api/customers/adjust-a-customers-account-balance.md) with `type` set to `opening_balance` |

## Look up a customer

Every endpoint finds the customer from the URL: `/api/v2/customers/{lookupBy}/{identifier}`.

| `lookupBy` | `identifier` |
| --- | --- |
| `sparklayer` | The customer's SparkLayer ID, the `id` in responses (a UUID). Legacy `cu_` IDs also work, except for shopping lists and favourites. |
| `platform` | The customer's ID on your eCommerce platform, their `external_id`, such as the Shopify customer ID. |
| `email` | The customer's email address. |

- **Email lookups are exact and case-sensitive.** URL-encode the address, and write `+` as `%2B`, or it's read as a space.
- **Inactive and archived customers are found**, and deleted customers aren't.

## Create and update customers

[Create or update a customer](https://docs.sparklayer.io/developers/api/customers/create-or-update-a-customer.md) (`PUT`) creates the customer if none matches, and otherwise replaces them.

- **The body must contain the identifier in the URL.** A `PUT` to `/api/v2/customers/platform/7843024560291` needs `"external_id": "7843024560291"`.
- **Send the whole customer every time.** Fields you leave out are cleared, and if you leave out `addresses`, every address is deleted. To change only some fields, use [Update a customer](https://docs.sparklayer.io/developers/api/customers/update-a-customer.md) (`PATCH`) instead.
- **`group` and `role` must exist.** Use `base` for the default customer group and `main` for a customer's main account. Price list slugs aren't checked, so make sure the price lists exist.
- **Emails and platform IDs are unique** across your customers, deleted customers aside. Reusing one returns `409`.

```json title="PUT /api/v2/customers/platform/7843024560291"
{
  "external_id": "7843024560291",
  "accounting_id": "C-1042",
  "email": "buyer@example.com",
  "first_name": "Sam",
  "last_name": "Taylor",
  "company_name": "Example Trading Ltd",
  "status": "active",
  "group": "base",
  "role": "main",
  "price_lists": ["trade-gbp"],
  "payment_on_account": {
    "credit_limit": 5000,
    "currency_code": "GBP",
    "net_terms": "30_days",
    "balance": 1250.00,
    "balance_date": "2026-11-01T00:00:00Z"
  },
  "addresses": [
    {
      "external_id": "addr-1042-1",
      "first_name": "Sam",
      "last_name": "Taylor",
      "company": "Example Trading Ltd",
      "address_line1": "1 Example Street",
      "city": "London",
      "region_code": null,
      "postal_code": "SW1A 1AA",
      "country_code": "GB"
    }
  ]
}
```

### Customer status

| `status` | What it means |
| --- | --- |
| `active` | The customer can sign in and buy. |
| `inactive` | The customer is kept, with their orders, but can't sign in. |
| `archived` | A former B2B customer, such as one whose `b2b` tag was removed in Shopify. They're kept, but left out of searches and sales reps' customer lists. |

## The account balance

When you use [pay on account](https://docs.sparklayer.io/help/ordering/credit-net-terms-and-invoicing.md), the balance in [My Account](https://docs.sparklayer.io/help/storefront/interfaces/my-account.md) comes from a ledger of entries for each customer. SparkLayer adds an entry for each order you send with the Purchasing API, and for each purchase transaction with `apply_to_balance`.

- **Without an opening balance**, the balance is every entry added together.
- **With an opening balance**, it's the opening balance plus the orders and payments dated on or after its date.

Set an opening balance with [Adjust a customer's account balance](https://docs.sparklayer.io/developers/api/customers/adjust-a-customers-account-balance.md), or with `balance` and `balance_date` in `payment_on_account` when you create or update the customer. Sending `payment_on_account` without `balance_date` sets the balance to `balance`, or 0 if you leave it out, as of now. Once a customer has an opening balance, these updates no longer change it.

## Endpoints

- [GET Get a customer](https://docs.sparklayer.io/developers/api/customers/get-a-customer.md)
- [PATCH Update a customer](https://docs.sparklayer.io/developers/api/customers/update-a-customer.md)
- [DELETE Delete a customer](https://docs.sparklayer.io/developers/api/customers/delete-a-customer.md)
- [PUT Create or update a customer](https://docs.sparklayer.io/developers/api/customers/create-or-update-a-customer.md)
- [PUT Set a customer's company roles](https://docs.sparklayer.io/developers/api/customers/set-a-customers-company-roles.md)
- [GET List a customer's addresses](https://docs.sparklayer.io/developers/api/customers/list-a-customers-addresses.md)
- [POST Create a customer address](https://docs.sparklayer.io/developers/api/customers/create-a-customer-address.md)
- [GET Get a customer address](https://docs.sparklayer.io/developers/api/customers/get-a-customer-address.md)
- [PATCH Update a customer address](https://docs.sparklayer.io/developers/api/customers/update-a-customer-address.md)
- [DELETE Delete a customer address](https://docs.sparklayer.io/developers/api/customers/delete-a-customer-address.md)
- [POST Adjust a customer's account balance](https://docs.sparklayer.io/developers/api/customers/adjust-a-customers-account-balance.md)
- [GET List shopping lists](https://docs.sparklayer.io/developers/api/customers/list-shopping-lists.md)
- [POST Create a shopping list](https://docs.sparklayer.io/developers/api/customers/create-a-shopping-list.md)
- [GET Get a shopping list](https://docs.sparklayer.io/developers/api/customers/get-a-shopping-list.md)
- [PATCH Update a shopping list](https://docs.sparklayer.io/developers/api/customers/update-a-shopping-list.md)
- [DELETE Delete a shopping list](https://docs.sparklayer.io/developers/api/customers/delete-a-shopping-list.md)
- [GET Get the favourites list](https://docs.sparklayer.io/developers/api/customers/get-the-favourites-list.md)
- [PUT Replace the favourites list](https://docs.sparklayer.io/developers/api/customers/replace-the-favourites-list.md)

## Next steps

- [Send orders to SparkLayer](https://docs.sparklayer.io/developers/api/purchasing/send-orders.md): build orders that show correctly in My Account and Pulse.
- [Authentication](https://docs.sparklayer.io/developers/authentication.md): get an access token for your requests.
- [Core API](https://docs.sparklayer.io/developers/api/core.md): customer groups, discounts and settings.
