Skip to content

Get Customer

GET /cdp/customers/{identifier} — fetch a single unified customer record that merges a customer’s behavioral CDP profile (from the CDP) with their commerce history (from the local synced store), joined by identity. One call returns the profile core, a commerce summary, the presence of your connected integrations, and subscription status.

Requires the beta:cdp-commerce permission on your brand.

GET /cdp/customers/{identifier}
Authorization: Bearer vyg_…
ParamTypeDescription
identifierstringA profile id, email, phone, Shopify customer id, or contact id. Classified by shape below.

The identifier is disambiguated by shape, deterministically:

ShapeInterpreted as
contains @email
starts with +phone
all digits (^\d+$)shopify_customer_id
a UUIDprofile_id, then contact_id
anything elseprofile_id (a CDP profile itemId)

A UUID is first tried as a CDP profile_id (a CDP profile itemId); if no profile matches, it is then tried as a contact_id — the local contacts.id that Customer Orders and List Orders return as customer.contact_id. This lets you join an order straight back to its customer with the id you already have. The CDP profile always takes precedence; matched_by tells you which resolved.

{
"identifier": "alice@example.com",
"matched_by": "email",
"scope": "your-shop.myshopify.com",
"profile": {
"id": "shopify_your-shop_5483611717768",
"provenance": "server",
"identity": {
"email": "alice@example.com",
"phoneNumber": "+14155550123",
"firstName": "Alice",
"shopifyCustomerId": "5483611717768",
"shopDomain": "your-shop.myshopify.com"
},
"segments": ["vip", "repeat-buyer"],
"behavior": {
"nb_of_visits": 12,
"first_visit": "2026-01-04T10:15:00.000Z",
"last_visit": "2026-06-30T18:02:00.000Z"
}
},
"commerce": {
"total_spend": "200.00",
"currency_code": "USD",
"order_count": 2,
"aov": "100.00",
"first_order_at": "2026-02-20T00:00:00.000Z",
"last_order_at": "2026-03-02T00:00:00.000Z"
},
"integrations": [
{
"id": "b1a2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"integration_id": "d1e3f5a7-2b4c-6d8e-0f1a-3c5e7b9d1f23",
"is_enabled": true,
"status": "connected",
"connected_at": "2026-01-01T00:00:00.000Z"
}
],
"subscription": {
"status": "active",
"active_count": 1,
"total_count": 1,
"next_billing_date": "2026-08-01T00:00:00.000Z"
}
}
FieldTypeDescription
identifierstringThe identifier you requested, echoed back.
matched_bystringWhich identity key resolved the local commerce contact: email, shopify_customer_id, phone, contact_id (a direct contacts.id match), or none.
scopestring | nullYour brand’s connected shop domain.
profileobject | nullThe CDP profile core, or null when no in-scope profile matched (commerce-only customer).
profile.provenancestringserver, pixel, or merged — how the profile entered the CDP.
profile.identityobjectProjected identity fields (email, phone, name, Shopify customer id, shop domain).
profile.segmentsarrayThe CDP segment ids the profile is a member of.
profile.behaviorobjectBehavioral rollups: nb_of_visits, first_visit, last_visit (each null when absent).
commerceobject | nullCommerce summary over the customer’s completed orders, or null when no commerce contact resolved.
commerce.total_spend / aovstringFixed-2 decimal money strings. aov = total_spend / order_count.
commerce.order_countintegerCount of completed orders.
commerce.first_order_at / last_order_atstring | nullEarliest / latest completed-order timestamps.
integrationsarrayPresence of your connected integrations — each entry carries id, integration_id, is_enabled, status, and connected_at only. integration_id is an opaque integration id (a UUID), not a provider name; resolve it to a provider via List Integrations. No credentials or settings are ever returned.
subscriptionobjectstatus (active / inactive / none), active_count, total_count, next_billing_date.

total_spend, order_count, and aov are computed over completed orders only (matching the platform’s GMV definition).

The profile and commerce halves are joined but independent, so a partial match returns the half that exists with null on the other:

  • A profile with no matching orderscommerce: null, subscription.status: "none", and matched_by: "none" — a 200, never an error.
  • Orders with no profileprofile: null, with commerce populated. This is the shape you get when you look a customer up by their contact_id (from an order): matched_by: "contact_id", no CDP profile, commerce populated.
Terminal window
curl -s "https://cdp.vyg.app/cdp/customers/alice@example.com" \
-H "Authorization: Bearer vyg_your_key_here"
StatusWhen
400Missing identifier.
401Missing or invalid credential.
403Brand not enrolled in the commerce beta (beta_not_enabled), or no connected Shopify integration (integration_not_connected).
404The customer is absent from both stores — an unknown identifier or one belonging to another brand, indistinguishable by design so a brand cannot probe for another brand’s customers.
405Non-GET method.
{
"error": "not_found",
"error_description": "Customer not found"
}

See Customer Orders for the customer’s order history, and Tenant Isolation & Scope for why out-of-scope identifiers return 404.