DevelopersAPI reference

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.

OperationEndpointRisk
A customer's 360: figures, health, behaviours and predictionsGET /organizations/{organizationId}/customers/{customerId}/insightsread
A customer's timelineGET /organizations/{organizationId}/customers/{customerId}/timelineread
Recompute a customer's insights nowPOST /organizations/{organizationId}/customers/{customerId}/insights/recomputewrite
Customers by lapse risk, late payment risk or quote acceptanceGET /organizations/{organizationId}/insights/predictionsread
Recompute the organization's insightsPOST /organizations/{organizationId}/insights/recomputewrite
Tag many customers (add to an automation audience)POST /organizations/{organizationId}/insights/bulk/tagwrite

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.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolinsights_customer (toolset customers)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

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
FieldTypeDescription
customerIdstring
computedAtstringWhen it was computed (ISO).
asOfstringThe business day it was computed for (YYYY-MM-DD).
versionintegerRules version.
summaryobject
summary.lifetimeValueCentsinteger or nullCollected, net of refunds, tips excluded. Null without invoice access.
summary.revenue12mCentsinteger or null
summary.averageTicketCentsinteger or null
summary.orderCountintegerIssued invoices (sent, paid or overdue).
summary.lastOrderDatestring or nullThe last issued invoice's day, YYYY-MM-DD.
summary.openQuoteCountintegerQuotes sent and waiting on the customer.
summary.openBalanceCentsinteger or null
summary.averageDaysToPayinteger or null
summary.customerSincestring
healthobject
health.scoreinteger0–100; 70 is a typical customer.
health.bandenumOne of GOOD, WATCH, AT_RISK.
health.driversarray of object
health.drivers[].keystring
health.drivers[].impactinteger
health.drivers[].detailstring
behavioursarray of object
behaviours[].keyenumOne 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[].evidencearray of string
predictionsarray of object
predictions[].kindenumLAPSE_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[].subjectTypeenum or nullWhat subjectId is: a quote (QUOTE_ACCEPTANCE); null for the customer. One of quote.
predictions[].subjectIdstringThe quote id; empty for the customer.
predictions[].likelihoodnumber0–1: how likely (lapse, late payment, acceptance).
predictions[].confidencenumber0–1: how much data stands behind it.
predictions[].levelenumOne of HIGH, MEDIUM, LOW.
predictions[].basisstring or nullQUOTE_ACCEPTANCE: the quote's Q-n; null otherwise.
predictions[].dueDatestring or nullYyyy-mm-dd: the next expected order (lapse risk), the next invoice due or the quote's expiry.
predictions[].windowStartstring or null
predictions[].windowEndstring or null
predictions[].reasonsarray of stringPlain-language reasons, most important first.
predictions[].dataUsedarray of objectThe records and figures it used.
predictions[].dataUsed[].labelstring
predictions[].dataUsed[].valuestring
linesarray of stringThe 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.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolinsights_timeline (toolset customers)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes
kindsquerystringNoComma-separated kinds to include: QUOTE, INVOICE, PAYMENT, MESSAGE, REVIEW, NOTE, REQUEST, CALL. Default: all you may see. Up to 200 characters.
cursorquerystringNoThe nextCursor of the previous page: the entries after it. Up to 500 characters.
beforequerystring (date-time)NoISO time: only entries that happened before it.
limitqueryintegerNo1–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
FieldTypeDescription
itemsarray of object
items[].idstringUnique per entry
items[].atstringWhen it happened in the business (ISO)
items[].occurredOnstringThe business day (YYYY-MM-DD)
items[].dateOnlybooleanOnly the day is known (imported or entered after the fact)
items[].recordedAtstringWhen the record was written (ISO)
items[].kindenumOne of QUOTE, INVOICE, PAYMENT, MESSAGE, REVIEW, NOTE, REQUEST, CALL.
items[].actionstring
items[].recordIdstring
items[].identifierstring or null
items[].titlestring
items[].detailstring or null
items[].amountCentsinteger or null
nextCursorstring or nullPass 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.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_recomputeCustomer (toolset customers)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

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
FieldTypeDescription
customerIdstring
computedAtstringWhen it was computed (ISO).
asOfstringThe business day it was computed for (YYYY-MM-DD).
versionintegerRules version.
summaryobject
summary.lifetimeValueCentsinteger or nullCollected, net of refunds, tips excluded. Null without invoice access.
summary.revenue12mCentsinteger or null
summary.averageTicketCentsinteger or null
summary.orderCountintegerIssued invoices (sent, paid or overdue).
summary.lastOrderDatestring or nullThe last issued invoice's day, YYYY-MM-DD.
summary.openQuoteCountintegerQuotes sent and waiting on the customer.
summary.openBalanceCentsinteger or null
summary.averageDaysToPayinteger or null
summary.customerSincestring
healthobject
health.scoreinteger0–100; 70 is a typical customer.
health.bandenumOne of GOOD, WATCH, AT_RISK.
health.driversarray of object
health.drivers[].keystring
health.drivers[].impactinteger
health.drivers[].detailstring
behavioursarray of object
behaviours[].keyenumOne 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[].evidencearray of string
predictionsarray of object
predictions[].kindenumLAPSE_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[].subjectTypeenum or nullWhat subjectId is: a quote (QUOTE_ACCEPTANCE); null for the customer. One of quote.
predictions[].subjectIdstringThe quote id; empty for the customer.
predictions[].likelihoodnumber0–1: how likely (lapse, late payment, acceptance).
predictions[].confidencenumber0–1: how much data stands behind it.
predictions[].levelenumOne of HIGH, MEDIUM, LOW.
predictions[].basisstring or nullQUOTE_ACCEPTANCE: the quote's Q-n; null otherwise.
predictions[].dueDatestring or nullYyyy-mm-dd: the next expected order (lapse risk), the next invoice due or the quote's expiry.
predictions[].windowStartstring or null
predictions[].windowEndstring or null
predictions[].reasonsarray of stringPlain-language reasons, most important first.
predictions[].dataUsedarray of objectThe records and figures it used.
predictions[].dataUsed[].labelstring
predictions[].dataUsed[].valuestring
linesarray of stringThe 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.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolinsights_predictions (toolset customers)
PlanCustomer 360 lists: the Grow plan and up.

Parameters

NameInTypeRequiredDescription
kindqueryenumYesOne of LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE.
minLikelihoodquerynumberNo0–1. Only predictions at least this likely.
minConfidencequerynumberNo0–1. Only predictions with at least this much data behind them.
levelqueryenumNoOne of HIGH, MEDIUM, LOW.
limitqueryintegerNoPage size, 1–200. Default 50.
offsetqueryintegerNoRows 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
FieldTypeDescription
totalinteger
itemsarray of object
items[].kindenumLAPSE_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[].subjectTypeenum or nullWhat subjectId is: a quote (QUOTE_ACCEPTANCE); null for the customer. One of quote.
items[].subjectIdstringThe quote id; empty for the customer.
items[].likelihoodnumber0–1: how likely (lapse, late payment, acceptance).
items[].confidencenumber0–1: how much data stands behind it.
items[].levelenumOne of HIGH, MEDIUM, LOW.
items[].basisstring or nullQUOTE_ACCEPTANCE: the quote's Q-n; null otherwise.
items[].dueDatestring or nullYyyy-mm-dd: the next expected order (lapse risk), the next invoice due or the quote's expiry.
items[].windowStartstring or null
items[].windowEndstring or null
items[].reasonsarray of stringPlain-language reasons, most important first.
items[].dataUsedarray of objectThe records and figures it used.
items[].dataUsed[].labelstring
items[].dataUsed[].valuestring
items[].customerIdstring
items[].customerNamestring

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.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_recompute (toolset customers)
PlanCustomer 360 lists: the Grow plan and up.

Request body

FieldTypeRequiredDescription
allbooleanNoRecompute everyone, not only stale ones.
limitintegerNoCustomers 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
FieldTypeDescription
addedinteger
recomputedinteger
remaininginteger

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.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_bulkTag (toolset customers)
PlanCustomer 360 lists: the Grow plan and up.

Request body

FieldTypeRequiredDescription
customerIdsarray of stringYesCustomer ids (e.g. from GET /insights/predictions), at most 100. Up to 100 items.
tagstringYesUp 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
FieldTypeDescription
requestedinteger
succeededinteger
skippedinteger
failedinteger
resultsarray of object
results[].customerIdstring
results[].outcomeenumOne of CREATED, UPDATED, SKIPPED, FAILED.
results[].recordIdstring or null
results[].identifierstring or null
results[].reasonstring or null

On this page