Customer insights API
REST endpoints for customer insights in SKUFlow: 6 operations with parameters, request and response fields, permissions and curl examples.
Base URL: https://app.skuflow.ai/api. Every call needs Authorization: Bearer skf_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.
| Operation | Endpoint | Risk |
|---|---|---|
| A customer's 360: figures, health, behaviours and predictions | GET /organizations/{organizationId}/customers/{customerId}/insights | read |
| A customer's timeline | GET /organizations/{organizationId}/customers/{customerId}/timeline | read |
| Recompute a customer's insights now | POST /organizations/{organizationId}/customers/{customerId}/insights/recompute | write |
| Customers by lapse risk, late payment risk or quote acceptance | GET /organizations/{organizationId}/insights/predictions | read |
| Recompute the organization's insights | POST /organizations/{organizationId}/insights/recompute | write |
| Tag many customers (add to an automation audience) | POST /organizations/{organizationId}/insights/bulk/tag | write |
A customer's 360: figures, health, behaviours and predictions
GET /organizations/{organizationId}/customers/{customerId}/insights
Customer 360 for one customer, computed from the business's own records: lifetime value, revenue in the last 12 months, average ticket, orders (issued invoices) and the last order, open quotes, open balance and days to pay; a 0–100 health score with its drivers; behaviours with their evidence (orders online, prefers text, pays late, price-sensitive, seasonal, promoter …); and predictions (lapse risk, late payment, each open quote's acceptance), each with likelihood, confidence, a due date or window, reasons and the data used. Use it to answer "why is this customer at risk" or "when will they order again". Recomputed first when stale; nothing else changes. Money figures need invoices.read.
| Permission | customers.read (Owner, Admin, Staff, Member) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | insights_customer (toolset customers) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
customerId | path | string | Yes |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/insights" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
customerId | string | |
computedAt | string | When it was computed (ISO). |
asOf | string | The business day it was computed for (YYYY-MM-DD). |
version | integer | Rules version. |
summary | object | |
summary.lifetimeValueCents | integer or null | Collected, net of refunds, tips excluded. Null without invoice access. |
summary.revenue12mCents | integer or null | |
summary.averageTicketCents | integer or null | |
summary.orderCount | integer | Issued invoices (sent, paid or overdue). |
summary.lastOrderDate | string or null | The last issued invoice's day, YYYY-MM-DD. |
summary.openQuoteCount | integer | Quotes sent and waiting on the customer. |
summary.openBalanceCents | integer or null | |
summary.averageDaysToPay | integer or null | |
summary.customerSince | string | |
health | object | |
health.score | integer | 0–100; 70 is a typical customer. |
health.band | enum | One of GOOD, WATCH, AT_RISK. |
health.drivers | array of object | |
health.drivers[].key | string | |
health.drivers[].impact | integer | |
health.drivers[].detail | string | |
behaviours | array of object | |
behaviours[].key | enum | One of BOOKS_ONLINE, BOOKS_BY_PHONE, PREFERS_TEXT, PREFERS_EMAIL, RESPONSIVE, UNRESPONSIVE, PAYS_ON_TIME, PAYS_LATE, QUICK_APPROVER, PRICE_SENSITIVE, SEASONAL, REVIEWER, PROMOTER, DETRACTOR, HIGH_VALUE. |
behaviours[].evidence | array of string | |
predictions | array of object | |
predictions[].kind | enum | LAPSE_RISK (overdue against their own ordering rhythm), LATE_PAYMENT (payment history) or QUOTE_ACCEPTANCE (one open quote). One of LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE. |
predictions[].subjectType | enum or null | What subjectId is: a quote (QUOTE_ACCEPTANCE); null for the customer. One of quote. |
predictions[].subjectId | string | The quote id; empty for the customer. |
predictions[].likelihood | number | 0–1: how likely (lapse, late payment, acceptance). |
predictions[].confidence | number | 0–1: how much data stands behind it. |
predictions[].level | enum | One of HIGH, MEDIUM, LOW. |
predictions[].basis | string or null | QUOTE_ACCEPTANCE: the quote's Q-n; null otherwise. |
predictions[].dueDate | string or null | Yyyy-mm-dd: the next expected order (lapse risk), the next invoice due or the quote's expiry. |
predictions[].windowStart | string or null | |
predictions[].windowEnd | string or null | |
predictions[].reasons | array of string | Plain-language reasons, most important first. |
predictions[].dataUsed | array of object | The records and figures it used. |
predictions[].dataUsed[].label | string | |
predictions[].dataUsed[].value | string | |
lines | array of string | The same in a few sentences. |
A customer's timeline
GET /organizations/{organizationId}/customers/{customerId}/timeline
Everything that happened with a customer, newest first by when it happened in the business (not when the record was entered): quotes when sent (else created) / approved / declined, invoices by issue day, payments by paid day, messages, replies, Google reviews, phone calls and notes by their own time, and requests. at is that moment; dateOnly entries (imported or entered after the fact) know only the day (occurredOn); recordedAt is when the record was written and breaks ties. Each kind appears only when your role may read its records. Page with cursor (the nextCursor of the previous page; stable, pages never overlap). Read-only.
| Permission | customers.read (Owner, Admin, Staff, Member) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | insights_timeline (toolset customers) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
customerId | path | string | Yes | |
kinds | query | string | No | Comma-separated kinds to include: QUOTE, INVOICE, PAYMENT, MESSAGE, REVIEW, NOTE, REQUEST, CALL. Default: all you may see. Up to 200 characters. |
cursor | query | string | No | The nextCursor of the previous page: the entries after it. Up to 500 characters. |
before | query | string (date-time) | No | ISO time: only entries that happened before it. |
limit | query | integer | No | 1–200. Default 50. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/timeline" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
items | array of object | |
items[].id | string | Unique per entry |
items[].at | string | When it happened in the business (ISO) |
items[].occurredOn | string | The business day (YYYY-MM-DD) |
items[].dateOnly | boolean | Only the day is known (imported or entered after the fact) |
items[].recordedAt | string | When the record was written (ISO) |
items[].kind | enum | One of QUOTE, INVOICE, PAYMENT, MESSAGE, REVIEW, NOTE, REQUEST, CALL. |
items[].action | string | |
items[].recordId | string | |
items[].identifier | string or null | |
items[].title | string | |
items[].detail | string or null | |
items[].amountCents | integer or null | |
nextCursor | string or null | Pass as cursor for the next page; null on the last page. |
Recompute a customer's insights now
POST /organizations/{organizationId}/customers/{customerId}/insights/recompute
Recomputes one customer's figures, behaviours and predictions from their records now (they are normally kept fresh automatically on every change and daily). Changes only the stored insight; nothing is sent. Returns the insight.
| Permission | customers.write (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | insights_recomputeCustomer (toolset customers) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
customerId | path | string | Yes |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/insights/recompute" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
customerId | string | |
computedAt | string | When it was computed (ISO). |
asOf | string | The business day it was computed for (YYYY-MM-DD). |
version | integer | Rules version. |
summary | object | |
summary.lifetimeValueCents | integer or null | Collected, net of refunds, tips excluded. Null without invoice access. |
summary.revenue12mCents | integer or null | |
summary.averageTicketCents | integer or null | |
summary.orderCount | integer | Issued invoices (sent, paid or overdue). |
summary.lastOrderDate | string or null | The last issued invoice's day, YYYY-MM-DD. |
summary.openQuoteCount | integer | Quotes sent and waiting on the customer. |
summary.openBalanceCents | integer or null | |
summary.averageDaysToPay | integer or null | |
summary.customerSince | string | |
health | object | |
health.score | integer | 0–100; 70 is a typical customer. |
health.band | enum | One of GOOD, WATCH, AT_RISK. |
health.drivers | array of object | |
health.drivers[].key | string | |
health.drivers[].impact | integer | |
health.drivers[].detail | string | |
behaviours | array of object | |
behaviours[].key | enum | One of BOOKS_ONLINE, BOOKS_BY_PHONE, PREFERS_TEXT, PREFERS_EMAIL, RESPONSIVE, UNRESPONSIVE, PAYS_ON_TIME, PAYS_LATE, QUICK_APPROVER, PRICE_SENSITIVE, SEASONAL, REVIEWER, PROMOTER, DETRACTOR, HIGH_VALUE. |
behaviours[].evidence | array of string | |
predictions | array of object | |
predictions[].kind | enum | LAPSE_RISK (overdue against their own ordering rhythm), LATE_PAYMENT (payment history) or QUOTE_ACCEPTANCE (one open quote). One of LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE. |
predictions[].subjectType | enum or null | What subjectId is: a quote (QUOTE_ACCEPTANCE); null for the customer. One of quote. |
predictions[].subjectId | string | The quote id; empty for the customer. |
predictions[].likelihood | number | 0–1: how likely (lapse, late payment, acceptance). |
predictions[].confidence | number | 0–1: how much data stands behind it. |
predictions[].level | enum | One of HIGH, MEDIUM, LOW. |
predictions[].basis | string or null | QUOTE_ACCEPTANCE: the quote's Q-n; null otherwise. |
predictions[].dueDate | string or null | Yyyy-mm-dd: the next expected order (lapse risk), the next invoice due or the quote's expiry. |
predictions[].windowStart | string or null | |
predictions[].windowEnd | string or null | |
predictions[].reasons | array of string | Plain-language reasons, most important first. |
predictions[].dataUsed | array of object | The records and figures it used. |
predictions[].dataUsed[].label | string | |
predictions[].dataUsed[].value | string | |
lines | array of string | The same in a few sentences. |
Customers by lapse risk, late payment risk or quote acceptance
GET /organizations/{organizationId}/insights/predictions
Customers ranked by one prediction, most likely first: LAPSE_RISK (churn: overdue against their own ordering rhythm, declined quotes, bad reviews), LATE_PAYMENT (payment history; needs invoices.read) or QUOTE_ACCEPTANCE (each open quote; needs quotes.read). Filter by likelihood (default 0.35), confidence and level. Read-only. Then POST /insights/bulk/tag to put them in an automation audience.
| Permission | customers.read (Owner, Admin, Staff, Member) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | insights_predictions (toolset customers) |
| Plan | Customer 360 lists: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
kind | query | enum | Yes | One of LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE. |
minLikelihood | query | number | No | 0–1. Only predictions at least this likely. |
minConfidence | query | number | No | 0–1. Only predictions with at least this much data behind them. |
level | query | enum | No | One of HIGH, MEDIUM, LOW. |
limit | query | integer | No | Page size, 1–200. Default 50. |
offset | query | integer | No | Rows to skip; the answer's total counts every match. Default 0. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/insights/predictions?kind=LAPSE_RISK" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
total | integer | |
items | array of object | |
items[].kind | enum | LAPSE_RISK (overdue against their own ordering rhythm), LATE_PAYMENT (payment history) or QUOTE_ACCEPTANCE (one open quote). One of LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE. |
items[].subjectType | enum or null | What subjectId is: a quote (QUOTE_ACCEPTANCE); null for the customer. One of quote. |
items[].subjectId | string | The quote id; empty for the customer. |
items[].likelihood | number | 0–1: how likely (lapse, late payment, acceptance). |
items[].confidence | number | 0–1: how much data stands behind it. |
items[].level | enum | One of HIGH, MEDIUM, LOW. |
items[].basis | string or null | QUOTE_ACCEPTANCE: the quote's Q-n; null otherwise. |
items[].dueDate | string or null | Yyyy-mm-dd: the next expected order (lapse risk), the next invoice due or the quote's expiry. |
items[].windowStart | string or null | |
items[].windowEnd | string or null | |
items[].reasons | array of string | Plain-language reasons, most important first. |
items[].dataUsed | array of object | The records and figures it used. |
items[].dataUsed[].label | string | |
items[].dataUsed[].value | string | |
items[].customerId | string | |
items[].customerName | string |
Recompute the organization's insights
POST /organizations/{organizationId}/insights/recompute
Recomputes stale customer insights now (normally done on every change and daily by the worker), up to limit customers; all marks every customer for recomputation first (after changing many records). Changes only stored insights; nothing is sent. Answers how many were recomputed and how many remain stale.
| Permission | customers.write (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | insights_recompute (toolset customers) |
| Plan | Customer 360 lists: the Grow plan and up. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
all | boolean | No | Recompute everyone, not only stale ones. |
limit | integer | No | Customers per call (default 500). 1–2000. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/insights/recompute" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"all":true,"limit":1}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
added | integer | |
recomputed | integer | |
remaining | integer |
Tag many customers (add to an automation audience)
POST /organizations/{organizationId}/insights/bulk/tag
Adds a tag to each customer (UPDATED, or SKIPPED when already tagged). An automation whose audience is "tags contains <tag>" then reaches exactly these customers. Nothing is sent by this call. Emits customer.updated per customer changed.
| Permission | customers.write (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | insights_bulkTag (toolset customers) |
| Plan | Customer 360 lists: the Grow plan and up. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
customerIds | array of string | Yes | Customer ids (e.g. from GET /insights/predictions), at most 100. Up to 100 items. |
tag | string | Yes | Up to 100 characters. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/insights/bulk/tag" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"customerIds":["customer_id"],"tag":"string"}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
requested | integer | |
succeeded | integer | |
skipped | integer | |
failed | integer | |
results | array of object | |
results[].customerId | string | |
results[].outcome | enum | One of CREATED, UPDATED, SKIPPED, FAILED. |
results[].recordId | string or null | |
results[].identifier | string or null | |
results[].reason | string or null |