Customer Insights
Lifetime value and spend totals for a single customer — resolved by profile id, email, phone, Shopify customer id, or contact id — over their completed orders.
GET /cdp/customers/{identifier}/insights — the lifetime value & spend summary
for a single customer, resolved from the same identifier as
Get Customer. Returns lifetime spend (ltv), order
count, average order value, and the first / last order timestamps at the top of
insights, plus the customer's RFM tier (insights.rfm), top products
(insights.top_products), and churn signal (insights.churn) inline.
Requires the beta:cdp-commerce permission on your brand.
What counts
Totals are computed over the customer's completed orders only
(state = "complete"). Orders in any other state — pending, cancelled, refunded —
are excluded. Amounts are denominated in the store's currency as
dollar-value decimal strings (e.g. "300.00", not cents).
Metrics are computed on read from your synced orders, so they always reflect your current data. The response contract is stable: if computation is later cached or materialized, the shape below does not change (a cache would carry at most a few minutes of staleness).
Request
GET /cdp/customers/{identifier}/insights
Authorization: Bearer vyg_…Path parameters
| Param | Type | Description |
|---|---|---|
identifier | string | A profile id, email, phone, Shopify customer id, or contact id — classified by shape (see Get Customer). |
Response 200
{
"identifier": "alice@example.com",
"matched_by": "email",
"scope": "your-shop.myshopify.com",
"insights": {
"ltv": "300.00",
"order_count": 3,
"aov": "100.00",
"first_order_at": "2026-01-10T00:00:00.000Z",
"last_order_at": "2026-03-20T00:00:00.000Z",
"currency_code": "USD",
"rfm": {
"recency_score": 5,
"frequency_score": 4,
"monetary_score": 4,
"tier": "champion",
"last_order_at": "2026-03-20T00:00:00.000Z",
"order_count": 3,
"ltv": "300.00"
},
"top_products": [
{
"product_id": "101",
"title": "Serum",
"quantity": 3,
"order_count": 2,
"customer_count": 1,
"revenue": "180.00",
"repeat_purchase_rate": 1
}
],
"churn": {
"days_since_last_order": 36,
"median_inter_order_days": 34,
"brand_median_inter_order_days": 30,
"at_risk": false,
"at_risk_score": 1.06
}
}
}| Field | Type | Description |
|---|---|---|
matched_by | string | Which identity key resolved the customer: email, shopify_customer_id, phone, contact_id, or none. |
scope | string | null | Your connected shop domain. |
insights.ltv | string | Lifetime spend — sum of completed-order totals, as a decimal string. |
insights.order_count | integer | Number of completed orders. |
insights.aov | string | Average order value = ltv / order_count, as a decimal string. |
insights.first_order_at | string | null | Timestamp of the earliest completed order, or null when there are none. |
insights.last_order_at | string | null | Timestamp of the latest completed order, or null when there are none. |
insights.currency_code | string | null | Currency of the completed orders, or null when there are none. |
insights.rfm | object | null | The customer's brand-relative RFM: recency_score, frequency_score, monetary_score (each 1–5), the derived tier, plus last_order_at, order_count, and ltv. null when the customer has no completed orders. See RFM. |
insights.top_products | array | The customer's top products by completed-order revenue (up to five), each with product_id, title, quantity, order_count, customer_count, revenue, and repeat_purchase_rate. Empty when the customer has no completed orders. See Product Insights. |
insights.churn | object | null | The customer's churn signal: days_since_last_order, median_inter_order_days, brand_median_inter_order_days, at_risk_score, and the at_risk boolean (true past roughly twice the cadence). null when the customer has no completed orders. See At-Risk Customers. |
A customer that resolves but has no completed orders yet returns the all-zero
summary (ltv: "0.00", order_count: 0, aov: "0.00", timestamps and
currency_code null), with rfm and churn null and top_products an empty
array — a clean "found the customer, no purchases yet", never a 404. matched_by
still reports the identity key that resolved the customer
(email, phone, shopify_customer_id, or contact_id); it is none only when
the identifier resolved a profile but no local commerce contact.
Example
curl -s "https://cdp.vyg.app/cdp/customers/alice@example.com/insights" \
-H "Authorization: Bearer vyg_your_key_here"Errors
| Status | When |
|---|---|
400 | Missing identifier. |
401 | Missing or invalid credential. |
403 | Brand not enrolled in the commerce beta (beta_not_enabled), or no connected Shopify integration (integration_not_connected). |
404 | The customer is absent from both the profile and commerce stores — an unknown identifier or one belonging to another brand, indistinguishable by design. |
405 | Non-GET method. |
See Brand LTV for the brand-wide aggregate, and
Tenant Isolation & Scope for why cross-brand
identifiers return 404 and never leak another brand's customers.