# GET /api/v2/customers

List customers

- MCP id: customers.index
- Scope: api:read:customers
- Permission: customers::read
- Rate cost: 1 unit, read bucket. `view=detail` makes it 3. Adds: each include +1 (to-many +3), `q` +2.
- Cache-Control: private, no-store

Returns the customers the caller may read, by name A-Z.

Defaults to the summary view; `view=detail` carries the same fields on this resource (no field of it is detail-only) and costs three read units instead of one. Search with `q=` over name, code and email, filter on the five reference ids, the status, the VAT flag and the three dates, and pass `trashed=with|only` to see deleted customers. `filter[account_manager_id]=me` is the "my customers" query. There is no relationship sort: `sort=customer_category.name` is a `400`.

## Parameters
- view (string, optional): Which field set to render.
- per_page (integer 1 to 100, optional): Rows per page. At most 25 when `include` names a to-many relation; a larger value is 400 invalid-query-parameter.
- cursor (string, optional): Opaque keyset cursor from a previous page's links.next. Never construct one by hand.
- page (integer 1 to 1000, optional): Opt in to page-number paging: 1-based, at most 1000. Omit it, the default, to page by opaque cursor, which is what links.next hands you. Cannot be combined with cursor. Published only on collections that count their rows on every request.
- filter[account_manager_id] (integer, optional): Responsible account manager. Accepts the literal `me`. Use the `null` operator to list customers with no account manager. Operators: = in null.
- filter[company_branch_id] (integer, optional): Industry branch. Operators: = in null.
- filter[company_size_id] (integer, optional): Company size band. Operators: = in null.
- filter[company_type_id] (integer, optional): Company type. Operators: = in null.
- filter[created_at] (timestamp (YYYY-MM-DDThh:mm:ssZ), optional): Creation timestamp. Pair with `sort=id` for a stable full export. Operators: = gte lt.
- filter[customer_category_id] (integer, optional): Customer category. Use the `null` operator to list uncategorised customers. Operators: = in null.
- filter[customer_since] (date (YYYY-MM-DD), optional): Day this customer became a customer. Operators: = gte lte null.
- filter[exact_keep_local_address] (boolean, optional): Whether the Exact sync leaves this customer's local address alone.
- filter[exact_synced_at] (timestamp (YYYY-MM-DDThh:mm:ssZ), optional): When the Exact sync last handled this customer. Use the `null` operator to list customers the sync has never touched. Operators: = gte lte null.
- filter[founded_at] (date (YYYY-MM-DD), optional): Day the customer's company was founded. Operators: = gte lte null.
- filter[is_vat_exempt] (boolean, optional): Whether invoices to this customer are issued without VAT.
- filter[status] (string, optional): Where the customer sits in the sales lifecycle. Operators: = ne in.
- filter[updated_at] (timestamp (YYYY-MM-DDThh:mm:ssZ), optional): Last-write timestamp. Use for incremental sync. Operators: = gte lt.
- q (string, optional): Free-text search over `name`, `code`, `email`, in that order of relevance. At most one substring match per request: `q` together with a `contains` filter is 400 invalid-query-parameter.
- sort (string, optional): Up to three keys, comma-separated, each optionally prefixed with `-` for descending.
- include (string, optional): Comma-separated names to inline, at most five.
- trashed (string, optional): Whether soft-deleted rows are included.
- X-Request-Id (header, optional): A correlation id of your own. It is recorded in our logs next to the server's request id but never returned: the response header always carries the server's id. A value that does not match the pattern is discarded silently, never rejected.
- If-None-Match (header, optional): The ETag a read is conditional on. A match is answered 304 with no body.

## Response 200
- id (integer, required): Unique identifier.
- name (string ≤ 255, required): Customer name. This is the default sort key and one of the fields `?q=` searches.
- code (string ≤ 255, required): Short customer code, e.g. ACM. Prefixes every work item's issue key, is enforced unique on write, and is one of the fields `?q=` searches.
- color (string ≤ 255, required): Chip colour as a CSS hex triplet or sextet, e.g. #1d4ed8. A stored value that is not valid hex reads back as #6b7280.
- status (string, required): Where the customer sits in the sales lifecycle.
- email (string or null ≤ 255, required): Primary email address. The third field `?q=` searches; not unique.
- phone (string or null ≤ 255, required): Phone number.
- address (string or null ≤ 255, required): Street address. Writing this, zip or city re-geocodes lat and lng.
- zip (string or null ≤ 255, required): Postal code.
- city (string or null ≤ 255, required): City.
- country (string or null ≤ 255, required): Country as an ISO 3166-1 alpha-2 code, e.g. NL, as plnnrly writes it. Older records may hold any string.
- lat (string or null ≤ 255, required, server-assigned): Latitude, geocoded from the address whenever address, zip or city changes. Not writable.
- lng (string or null ≤ 255, required, server-assigned): Longitude, geocoded from the address whenever address, zip or city changes. Not writable.
- founded_at (date (YYYY-MM-DD) or null, required): Day the customer's company was founded.
- customer_since (date (YYYY-MM-DD) or null, required): Day this customer became a customer.
- is_vat_exempt (boolean, required): Whether invoices to this customer are issued without VAT.
- payment_days (integer or null, required, server-assigned): Payment term in days, as held by the accounting integration. Read by the invoice composer; written only by the Exact sync.
- debtor_code (string or null ≤ 255, required): Debtor number in the accounting system. Writing it requires `billing_settings::update`.
- exact_account_id (string or null ≤ 255, required, server-assigned): Account identifier in Exact Online, written by the sync.
- exact_synced_at (timestamp (YYYY-MM-DDThh:mm:ssZ) or null, required, server-assigned): When the Exact sync last handled this customer, or `null` if never.
- exact_keep_local_address (boolean, required, server-assigned): Whether the Exact sync leaves this customer's local address alone although it differs from the one in Exact. Set when a user accepts the difference on the Exact customers screen in plnnrly; not writable.
- account_manager_id (integer or null, required): Responsible account manager. Required on create; unassigned when the user is deleted.
- customer_category_id (integer or null, required): Customer category, or `null`.
- company_type_id (integer or null, required): Company type, or `null`. Company types are your organisation's own list, maintained in plnnrly and not exposed as a collection.
- company_size_id (integer or null, required): Company size band, or `null`. Company sizes are your organisation's own list, maintained in plnnrly and not exposed as a collection.
- company_branch_id (integer or null, required): Industry branch, or `null`.
- created_at (timestamp (YYYY-MM-DDThh:mm:ssZ), required): Creation timestamp.
- updated_at (timestamp (YYYY-MM-DDThh:mm:ssZ), required): Last-write timestamp; use for incremental sync.
- deleted_at (timestamp (YYYY-MM-DDThh:mm:ssZ) or null, required): Soft-delete timestamp, `null` while live.
- customer_category (Ref or CustomerCategorySummary or null, required): The customer's category. Rendered as {"id": N} until named in `?include=customer_category`, and `null` where none is assigned.
- company_branch (Ref or CompanyBranchSummary or null, required): The customer's industry branch. Rendered as {"id": N} until named in `?include=company_branch`, and `null` where none is assigned.
- projects_count (integer ≥ 0, required): Number of live projects for this customer. Soft-deleted projects are not counted.
- contacts_count (integer ≥ 0, required): Number of contacts on this customer.
- tags_count (integer ≥ 0, required): Number of tags on this customer.
- links (CustomerLinks, required)
  - self (url, required): The canonical URI of this record.
  - projects (url, required): Projects for this customer.
  - contacts (url, required): Contacts on this customer.
- tags (array of TagSummary ≤ 50, optional, only with include): Tags on this customer. A customer takes at most 50 tags, so the include lists them all. `tag_ids` replaces the whole set. Wrapped in `{ data, meta }`; `meta.truncated` says whether the cap was hit and `meta.count` is the full count.
  - id (integer, required): Unique identifier.
  - title (string ≤ 255, required): Tag title as shown in the UI.

## Errors
- 403 forbidden-by-policy | insufficient-permission | insufficient-token-scope: Forbidden.
- 304 : Not modified.
- 400 idempotency-key-required | invalid-cursor | invalid-query-parameter | malformed-request | unsupported-parameter: Bad request.
- 401 token-expired | unauthenticated: Unauthenticated.
- 404 endpoint-not-found | resource-not-found: Not found.
- 406 not-acceptable: Not acceptable.
- 429 rate-limit-exceeded: Too many requests.
- 500 internal-error: Server error.
- 503 tenant-unavailable: Service unavailable.

## Example
```bash
curl -G \
  'https://<your-url>/api/v2/customers' \
  --data-urlencode 'filter[status]=active' \
  --data-urlencode 'filter[account_manager_id]=me' \
  --data-urlencode 'sort=customer_since' \
  --data-urlencode 'include=customer_category,tags' \
  -H 'Authorization: Bearer <token>' \
  -H 'Accept: application/json'
```
