Skip to content

Customers API Overview

The Customers API gives partners access to customer data — name, contact details, customer type, primary address, organization/contact relationships, and a search-by-email-or-mobile lookup.

All request/response examples use placeholder values; field names and types match what the API returns.


https://<store-url>/public/customers/v1

<store-url> is the base URL issued to your store, per environment (sandbox / production). See Getting Started → Base URL for the full list of hosts. All paths below are relative to it.


Every request must be authenticated. You need two credentials on each call:

Header Value Purpose
Authorization Bearer <access_token> OAuth 2.0 JWT access token
Ocp-Apim-Subscription-Key <your-subscription-key> Identifies your subscription at the API gateway
  • The access token must carry the customer:read scope. A token without it is rejected with 403 Forbidden.
  • Tokens are short-lived (typically 30–60 minutes). Request a new token when the old one expires.
  • For details on obtaining a token, supported authorities, and the claims involved, see Getting Started → Authentication.

Beyond the scope check, per-customer access control applies: you only see customers your account is entitled to. On Get customer by ID and Get the organization a contact buys under, requesting a customer you aren’t entitled to returns 403 Forbidden. Search customers instead filters silently: a match you aren’t entitled to is just missing from the result array, not reported as an error — see the note there.


  • Format: JSON only (Accept: application/json). Field names are camelCase.
  • Optional fields are omitted from the payload entirely when not applicable — not serialized as null. email, mobile, primaryAddress, organizationNumber, and organizationData may all be absent from a response.
  • customerId, name, customerType, country, isB2B, and isPublic are never omitted and never null — every response has all six, always. customerType is always "Person" or "Organization" — every customer has one of the two. name comes back as an empty string ("") when we have no value on record; customerId, country, isB2B, and isPublic are always meaningful — customerId is never empty, country is always a real, uppercase ISO 3166-1 alpha-2 country code, and the booleans are always computed, never “no value on record.” See Response model.
  • primaryAddress’s own fields follow a different rule once primaryAddress itself is present: streetLine1, postalCode, city, and country are never omitted and never null, but — unlike the top-level country above — fall back to an empty string ("") when we have no value on record. Only streetLine2 inside it is independently optional.
  • Each response carries an X-Trace-Id header. Quote it when contacting support — it lets us correlate your request with our logs.

Method Path Scope Description
GET /customers/v1/{customerId} customer:read Retrieve a single customer by ID
GET /customers/v1/{contactId}/organization customer:read Get the organization a contact buys under
GET /customers/v1/{organizationId}/contacts customer:read Get the contacts who can buy under an organization
GET /customers/v1 customer:read Search customers by email and/or mobile

GET /customers/v1/{customerId}

Retrieves a single customer by their unique ID.

Path parameters

Name Type Required Description
customerId string (GUID) yes The unique identifier of the customer.

Responses

Status Meaning
200 OK Customer found and you are entitled to see it. Body is { "customer": ... } — see Response model.
400 Bad Request customerId was empty or not a valid GUID.
401 Unauthorized Missing or invalid token.
403 Forbidden Token lacks customer:read, or you are not entitled to this customer.
404 Not Found No customer exists with that GUID — or it exists but isn’t visible (see note below).
500 Internal Server Error Unexpected server error.

404 doesn’t distinguish “doesn’t exist” from “exists but isn’t visible.” A customer that has been archived or removed returns the same 404 Not Found as a GUID that was never valid. The response deliberately doesn’t reveal which case you hit.

Example response (200 OK)

{
"customer": {
"customerId": "11111111-1111-1111-1111-111111111111",
"name": "Ada Lovelace",
"email": "ada.lovelace@example.com",
"mobile": "91234567",
"customerType": "Person",
"isB2B": false,
"isPublic": true,
"country": "NO",
"primaryAddress": {
"streetLine1": "Enigmavegen 1",
"postalCode": "0001",
"city": "Oslo",
"country": "NO"
}
}
}

A business customer looks the same, with isB2B: true, customerType: "Organization", and (when on record) organizationNumber/organizationData populated — see Response model. Any optional field not on record is omitted, not null — except customerId, name, customerType, country, isB2B, and isPublic, which are never omitted (see Conventions).

Example response (404 Not Found)

{
"type": "<docs-base-url>/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Customer '11111111-1111-1111-1111-111111111111' either does not exist or is archived or removed.",
"instance": "/customers/v1/11111111-1111-1111-1111-111111111111",
"code": "ERR_NOTFOUND",
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

2. Get the organization a contact buys under

Section titled “2. Get the organization a contact buys under”
GET /customers/v1/{contactId}/organization

Retrieves the organization associated with a contact — for example, the company an employee or customer contact buys under.

Path parameters

Name Type Required Description
contactId string (GUID) yes The customer ID of the contact (same value accepted by GET /customers/v1/{customerId}).

Responses

Status Meaning
200 OK Organization found and you are entitled to see it. Body is { "organization": ... }, the customer shape describing the organization.
400 Bad Request contactId was empty or not a valid GUID.
401 Unauthorized Missing or invalid token.
403 Forbidden Token lacks customer:read.
404 Not Found Contact has no associated organization — or one exists but isn’t visible to you (see note below).
500 Internal Server Error Unexpected server error.

404 doesn’t distinguish “no organization” from “exists but you can’t see it” from “not a contact at all.” contactId isn’t checked against customerType — passing an Organization’s own ID, or a Person who isn’t a contact of any organization, produces the same 404 Not Found as a genuine contact with no organization, or one you aren’t entitled to read. The response deliberately doesn’t reveal which case you hit.

Example response (200 OK)

{
"organization": {
"customerId": "22222222-2222-2222-2222-222222222222",
"name": "Rubber Duck Enterprises AS",
"customerType": "Organization",
"isB2B": true,
"isPublic": false,
"country": "NO",
"organizationNumber": "923609016",
"organizationData": {
"subOrganizationName": "Rubber Duck Enterprises",
"subOrganizationNumber": "923609016-1",
"organizationCountry": "NO",
"organizationIds": {}
}
}
}

Example response (404 Not Found)

{
"type": "<docs-base-url>/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Contact '11111111-1111-1111-1111-111111111111' has no associated organization.",
"instance": "/customers/v1/11111111-1111-1111-1111-111111111111/organization",
"code": "ERR_NOTFOUND",
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

3. Get the contacts who can buy under an organization

Section titled “3. Get the contacts who can buy under an organization”
GET /customers/v1/{organizationId}/contacts

Retrieves the persons associated with an organization. Empty array if the organization has none.

Path parameters

Name Type Required Description
organizationId string (GUID) yes The customer ID of the organization (same value accepted by GET /customers/v1/{customerId}).

Responses

Status Meaning
200 OK List of contacts you’re entitled to see. Body is { "contacts": [...] }, an array of customer objects — empty if the organization has no contacts, or none are visible.
400 Bad Request organizationId was empty or not a valid GUID.
401 Unauthorized Missing or invalid token.
403 Forbidden Token lacks customer:read, or you are not entitled to this organization.
500 Internal Server Error Unexpected server error.

If you’re entitled to read the organization, you get every contact under it. An organization with no contacts returns 200 OK with an empty array, not 404.

Example response (200 OK)

{
"contacts": [
{
"customerId": "11111111-1111-1111-1111-111111111111",
"name": "Ada Lovelace",
"email": "ada.lovelace@example.com",
"customerType": "Person",
"isB2B": false,
"isPublic": true,
"country": "NO"
},
{
"customerId": "33333333-3333-3333-3333-333333333333",
"name": "Grace Hopper",
"customerType": "Person",
"isB2B": false,
"isPublic": true,
"country": ""
}
]
}

GET /customers/v1?email={email}&mobile={mobile}&customerType={customerType}&pageSize={pageSize}&continuationToken={continuationToken}

Searches customers by email and/or mobile, scoped to your own store. At least one of email or mobile is required.

Query parameters

Name Type Required Description
email string one of email/mobile Email address to search for. At most 254 characters, must be a valid email address.
mobile string one of email/mobile Mobile number to search for. 5–14 digits, no formatting characters (no +, spaces, or dashes).
customerType string no Filter results to Person or Organization. Applied after the search, so it doesn’t narrow what counts as a match on email/mobile.
pageSize integer no Page size, 1–100. Null uses the server default.
continuationToken string no Opaque token from a previous response, used to fetch the next page.

Responses

Status Meaning
200 OK List of matching customers you’re entitled to see. Body is { "customers": [...], "continuationToken": ... } — see Pagination.
400 Bad Request Neither email nor mobile was set, one was set but malformed, or pageSize is outside 1–100.
401 Unauthorized Missing or invalid token.
403 Forbidden Token lacks customer:read.
500 Internal Server Error Unexpected server error.

Search is always scoped to your own store.

Unlike Get customer by ID, a match you aren’t entitled to never produces a 403 here — it’s silently dropped from the customers array instead. Each match is checked individually, so a search can return fewer results than it found, with no way to tell from the response alone that anything was filtered out.

Example response (200 OK)

{
"customers": [
{
"customerId": "11111111-1111-1111-1111-111111111111",
"name": "Ada Lovelace",
"email": "ada.lovelace@example.com",
"mobile": "91234567",
"customerType": "Person",
"isB2B": false,
"isPublic": true,
"country": "NO"
}
],
"continuationToken": null
}

Search is cursor-based, not page-numbered:

  1. A response includes continuationToken when more results may be available, or null at the end.
  2. To fetch the next page, repeat the same request and pass the token back as the continuationToken query parameter.
  3. Per-customer access control is applied after paging. Because of this, a page may contain fewer than pageSize customers, or be empty, while still returning a non-null continuationToken — see the entitlement note above. An empty page does not mean you are done; keep following continuationToken until it is null.

Example response (400 Bad Request)

{
"type": "<docs-base-url>/errors/validation-failed",
"title": "Validation Failed",
"detail": "Some fields have validation errors",
"status": 400,
"instance": "/customers/v1",
"code": "ERR_VALIDATION_0001",
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
"errors": [
{ "fieldName": "Email", "message": "At least one of Email or Mobile must be set." }
]
}

Every endpoint wraps its result in an envelope object, matching Orders’ and KomplettPc’s convention — none of these endpoints return a bare object or array at the top level:

Endpoint Envelope
Get customer by ID { "customer": Customer }
Get the organization a contact buys under { "organization": Customer }
Get the contacts who can buy under an organization { "contacts": Customer[] }
Search customers { "customers": Customer[], "continuationToken": string | null }

All four wrap the same underlying shape — a single customer/organization/contact object, described once below as Customer.

Customer

Field Type Description
customerId string The customer’s (or organization’s, or contact’s) unique identifier. Never null, never omitted, never empty.
name string Name. Empty string ("") when we have none on record — never null, never omitted.
email string Email address. Omitted if not on record.
mobile string Mobile phone number. Omitted if not on record.
customerType "Person" | "Organization" Customer type. Every customer has one of these two values. Never null, never omitted.
isB2B boolean Whether this is a business customer. Never null, never omitted.
isPublic boolean Whether the organization is a public-sector entity (government, municipality, public school, kindergarten, etc.). Always false for "Person" customers. Never null, never omitted.
country string Uppercase ISO 3166-1 alpha-2 country code. Never null, never omitted, never empty.
primaryAddress Address The customer’s primary address, if on record. Omitted if not.
organizationNumber string Populated only when customerType is "Organization". Omitted otherwise.
organizationData OrganizationData Populated only when customerType is "Organization". Omitted otherwise.

Present only when primaryAddress itself is present.

Field Type Description
streetLine1 string Street address line 1. Empty string when we have none on record — never null, never omitted once primaryAddress is present.
streetLine2 string Street address line 2. Omitted if not on record.
postalCode string Postal code. Empty string when we have none on record — never null, never omitted once primaryAddress is present.
city string City. Empty string when we have none on record — never null, never omitted once primaryAddress is present.
country string Uppercase ISO 3166-1 alpha-2 country code. Empty string when we have none on record — never null, never omitted once primaryAddress is present.

Present only when organizationData itself is present. Every field is omitted if not on record.

Field Type Description
subOrganizationName string Sub-organization name, if any.
subOrganizationNumber string Sub-organization number, if any.
organizationCountry string Organization’s uppercase ISO 3166-1 alpha-2 country code, if any.
organizationIds object (string → string) Additional organization identifiers, keyed by id type — see Organization identifier types.

Which key(s) can appear in organizationIds depends on the organization’s country. The top-level organizationNumber field always holds the country’s primary registration number; whether that same value is also duplicated into organizationIds varies by country and isn’t predictable from one country’s behavior:

  • Norway: organizationIds is typically empty — the number lives only in the top-level organizationNumber field.
  • Denmark: organizationNumber and organizationIds["CVR"] hold the same value — the number is duplicated into both places.
  • Sweden: organizationNumber and organizationIds["OrganizationNumber"] hold the same value, same duplication pattern as Denmark. VAT is only added separately when it differs from the organization number.
Country Key(s) in organizationIds Format
Norway (NO) OrganizationNumber 9 digits
Sweden (SE) VAT, OrganizationNumber VAT only present when it differs from organizationNumber
Denmark (DK) CVR 8 digits
Finland (FI) BusinessID 1234567-8 (7 digits + hyphen + check digit)
Poland (PL) NIP, REGON, KRS NIP: 10 digits · REGON: 9 or 14 digits · KRS: 10 digits
Lithuania (LT) CompanyCode, PVM CompanyCode: 7 or 9 digits · PVM: LT + 9 or 12 digits
Latvia (LV) CompanyRegistrationNumber 11 digits, starts with 4
Ireland (IE) CRO, TRN CRO: 6–8 digits, may include a leading letter · TRN: 7 digits + 1–2 letters
Estonia (EE) CompanyRegistrationCode, VAT CompanyRegistrationCode: 8 digits
Germany (DE) VAT, HRB HRB: HRB + 1–5 digits

All errors use the RFC 9457 / RFC 7807 Problem Details JSON format.

Problem Details

Field Type Description
type string (URI) Identifies the error category.
title string Short, human-readable summary of the category.
detail string Human-readable explanation specific to this occurrence.
status integer HTTP status code.
instance string The request path that produced the error.
code string Stable machine-readable error code (see table below).
traceId string Correlation id; also returned in the X-Trace-Id header. Quote it to support.

Validation errors (400) include an additional errors array, one entry per invalid field:

{
"type": "<docs-base-url>/errors/validation-failed",
"title": "Validation Failed",
"detail": "Some fields have validation errors",
"status": 400,
"instance": "/customers/v1/not-a-guid",
"code": "ERR_VALIDATION_0001",
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
"errors": [
{ "fieldName": "CustomerId", "message": "CustomerId must be a valid GUID." }
]
}

Status / code reference

HTTP status code When it happens
400 Bad Request ERR_VALIDATION_0001 A required id/query field was missing or malformed. See errors[].
401 Unauthorized — Missing, malformed, or expired token / wrong auth scheme.
403 Forbidden ERR_ACCESS Token lacks customer:read, or (endpoints 1 and 3 only) you aren’t entitled to the requested customer/organization.
404 Not Found ERR_NOTFOUND No customer exists with the given id, or it/its relationship isn’t visible to you (see each endpoint above for specifics).
500 Internal Server Error InternalServerError Unexpected server error. Retry later; quote the trace id if it persists.

Terminal window
curl -s "https://<store-url>/public/customers/v1/11111111-1111-1111-1111-111111111111" \
-H "Authorization: Bearer <access_token>" \
-H "Ocp-Apim-Subscription-Key: <subscription_key>" \
-H "Accept: application/json"
Terminal window
curl -s "https://<store-url>/public/customers/v1?email=ada.lovelace%40example.com" \
-H "Authorization: Bearer <access_token>" \
-H "Ocp-Apim-Subscription-Key: <subscription_key>" \
-H "Accept: application/json"