DevelopersAPI reference

Customer insights API

REST endpoints for customer insights in ServFlo: 12 operations with parameters, request and response fields, permissions and curl examples.

Base URL: https://app.servflo.ai/api. Every call needs Authorization: Bearer sfk_… (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 due for serviceGET /organizations/{organizationId}/insights/service-dueread
Equipment likely to need replacingGET /organizations/{organizationId}/insights/replacementsread
Customers by lapse risk, late payment risk or quote acceptanceGET /organizations/{organizationId}/insights/predictionsread
Recompute the organization's insightsPOST /organizations/{organizationId}/insights/recomputewrite
The equipment lifespan tableGET /organizations/{organizationId}/insights/lifespansread
Change equipment lifespansPATCH /organizations/{organizationId}/insights/lifespanswrite
Create service requests for many customersPOST /organizations/{organizationId}/insights/bulk/requestswrite
Create replacement quotes for many customersPOST /organizations/{organizationId}/insights/bulk/quoteswrite
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, jobs and the last / next visit, membership, open balance and days to pay; a 0–100 health score with its drivers; behaviours with their evidence (books online, prefers text, pays late, price-sensitive, seasonal, member, promoter …); each piece of equipment's age and replacement outlook; and predictions (next service due, equipment replacement, 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 are they due". Recomputed first when stale; nothing else changes. Technicians see only customers on their jobs and no money figures.

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

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/insights" \
  -H "Authorization: Bearer $SERVFLO_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.jobCountinteger
summary.completedJobCountinteger
summary.lastVisitDatestring or null
summary.nextVisitDatestring or null
summary.membershipobject or null
summary.membership.idstring
summary.membership.identifierstring
summary.membership.planNamestring
summary.membership.statusstring
summary.membership.endDatestring
summary.membership.autoRenewboolean
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, AUTOPAY, QUICK_APPROVER, PRICE_SENSITIVE, SEASONAL, MEMBER, REVIEWER, PROMOTER, DETRACTOR, HIGH_VALUE.
behaviours[].evidencearray of string
equipmentarray of object
equipment[].assetIdstring
equipment[].namestring
equipment[].propertyIdstring or null
equipment[].equipmentTypestring
equipment[].typeInferredbooleanThe type was read from the name: set it on the equipment to be sure.
equipment[].installYearinteger or null
equipment[].ageYearsnumber or null
equipment[].lifespanYearsinteger
equipment[].lifeUsednumber or nullAge divided by the lifespan.
equipment[].refrigerantTypestring or null
equipment[].conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
equipment[].repairs24minteger
equipment[].repairCost24mCentsinteger
equipment[].likelihoodnumber
equipment[].levelenumOne of HIGH, MEDIUM, LOW.
equipment[].outlookenumOne of REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE.
predictionsarray of object
predictions[].kindenumOne of SERVICE_DUE, EQUIPMENT_REPLACEMENT, LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE.
predictions[].subjectTypeenum or nullWhat subjectId is: equipment or a quote. One of asset, quote.
predictions[].subjectIdstringThe asset or quote id; empty for the customer.
predictions[].likelihoodnumber0–1: how likely (replacement, lapse, late payment, acceptance). Always 1 for SERVICE_DUE.
predictions[].confidencenumber0–1: how much data stands behind it.
predictions[].levelenumOne of HIGH, MEDIUM, LOW.
predictions[].basisstring or nullSERVICE_DUE: BOOKED, MEMBERSHIP, CADENCE, INTERVAL, SEASONAL or ANNUAL. Replacement: REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE. Quote: its Q-n.
predictions[].dueDatestring or nullYyyy-mm-dd: service due, end of life, the next expected visit, 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): jobs and visits by their scheduled or service day, quotes when sent (else created) / approved / declined, invoices by issue day, payments by paid day, messages, replies, Google reviews and notes by their own time, requests and memberships. 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, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolinsights_timeline (toolset customers)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes
kindsquerystringNoComma-separated kinds to include: JOB, QUOTE, INVOICE, PAYMENT, MESSAGE, REVIEW, NOTE, REQUEST, MEMBERSHIP, 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.servflo.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/timeline" \
  -H "Authorization: Bearer $SERVFLO_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 JOB, QUOTE, INVOICE, PAYMENT, MESSAGE, REVIEW, NOTE, REQUEST, MEMBERSHIP, 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, Dispatcher)
Riskwrite, OAuth scope servflo.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.servflo.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/insights/recompute" \
  -H "Authorization: Bearer $SERVFLO_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.jobCountinteger
summary.completedJobCountinteger
summary.lastVisitDatestring or null
summary.nextVisitDatestring or null
summary.membershipobject or null
summary.membership.idstring
summary.membership.identifierstring
summary.membership.planNamestring
summary.membership.statusstring
summary.membership.endDatestring
summary.membership.autoRenewboolean
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, AUTOPAY, QUICK_APPROVER, PRICE_SENSITIVE, SEASONAL, MEMBER, REVIEWER, PROMOTER, DETRACTOR, HIGH_VALUE.
behaviours[].evidencearray of string
equipmentarray of object
equipment[].assetIdstring
equipment[].namestring
equipment[].propertyIdstring or null
equipment[].equipmentTypestring
equipment[].typeInferredbooleanThe type was read from the name: set it on the equipment to be sure.
equipment[].installYearinteger or null
equipment[].ageYearsnumber or null
equipment[].lifespanYearsinteger
equipment[].lifeUsednumber or nullAge divided by the lifespan.
equipment[].refrigerantTypestring or null
equipment[].conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
equipment[].repairs24minteger
equipment[].repairCost24mCentsinteger
equipment[].likelihoodnumber
equipment[].levelenumOne of HIGH, MEDIUM, LOW.
equipment[].outlookenumOne of REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE.
predictionsarray of object
predictions[].kindenumOne of SERVICE_DUE, EQUIPMENT_REPLACEMENT, LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE.
predictions[].subjectTypeenum or nullWhat subjectId is: equipment or a quote. One of asset, quote.
predictions[].subjectIdstringThe asset or quote id; empty for the customer.
predictions[].likelihoodnumber0–1: how likely (replacement, lapse, late payment, acceptance). Always 1 for SERVICE_DUE.
predictions[].confidencenumber0–1: how much data stands behind it.
predictions[].levelenumOne of HIGH, MEDIUM, LOW.
predictions[].basisstring or nullSERVICE_DUE: BOOKED, MEMBERSHIP, CADENCE, INTERVAL, SEASONAL or ANNUAL. Replacement: REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE. Quote: its Q-n.
predictions[].dueDatestring or nullYyyy-mm-dd: service due, end of life, the next expected visit, 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 due for service

GET /organizations/{organizationId}/insights/service-due

Who needs service, and when: each customer's predicted next service date (from a membership visit, their own cadence, the service type's interval or the season) within from–to (default: 30 days overdue to 60 days ahead), soonest first, with reasons. Customers with a visit already booked are left out unless includeBooked. Answers "who needs service next month". Read-only. Then POST /insights/bulk/requests, /insights/bulk/tag.

Permissioncustomers.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolinsights_serviceDue (toolset customers)

Parameters

NameInTypeRequiredDescription
fromquerystringNoA calendar date in the business's own calendar, YYYY-MM-DD.
toquerystringNoA calendar date in the business's own calendar, YYYY-MM-DD.
includeBookedqueryenumNotrue: include customers with a visit already booked. One of true, false.
memberOnlyqueryenumNotrue: active members only. One of true, false.
basisqueryenumNoOne of MEMBERSHIP, CADENCE, INTERVAL, SEASONAL, ANNUAL, BOOKED.
serviceTypeIdquerystringNoCustomers who have had this service.
minConfidencequerynumberNo0–1. Only predictions with at least this much data behind them.
limitqueryintegerNoPage size, 1–200. Default 50.
offsetqueryintegerNoRows to skip; the answer's total counts every match. Default 0.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/service-due" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
todaystring
fromstring
tostring
totalinteger
itemsarray of object
items[].kindenumOne of SERVICE_DUE, EQUIPMENT_REPLACEMENT, LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE.
items[].subjectTypeenum or nullWhat subjectId is: equipment or a quote. One of asset, quote.
items[].subjectIdstringThe asset or quote id; empty for the customer.
items[].likelihoodnumber0–1: how likely (replacement, lapse, late payment, acceptance). Always 1 for SERVICE_DUE.
items[].confidencenumber0–1: how much data stands behind it.
items[].levelenumOne of HIGH, MEDIUM, LOW.
items[].basisstring or nullSERVICE_DUE: BOOKED, MEMBERSHIP, CADENCE, INTERVAL, SEASONAL or ANNUAL. Replacement: REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE. Quote: its Q-n.
items[].dueDatestring or nullYyyy-mm-dd: service due, end of life, the next expected visit, 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
items[].phonestring or null
items[].emailstring or null
items[].healthScoreinteger or null
items[].lastVisitDatestring or null
items[].memberboolean
items[].overduebooleanDue before today.

Equipment likely to need replacing

GET /organizations/{organizationId}/insights/replacements

Equipment most likely to need replacing, most likely first: age against its expected lifespan (the organization's lifespan table), repairs and their cost in the last 24 months, R-22 refrigerant, condition and notes, with reasons and the data used. Filter by likelihood (default 0.35), level, equipment type, minimum age, members. Read-only. Then POST /insights/bulk/quotes or /insights/bulk/tag.

Permissioncustomers.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolinsights_replacements (toolset customers)

Parameters

NameInTypeRequiredDescription
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.
equipmentTypequeryenumNoOne of AC, HEAT_PUMP, FURNACE, BOILER, MINI_SPLIT, AIR_HANDLER, PACKAGE_UNIT, WATER_HEATER, TANKLESS_WATER_HEATER, THERMOSTAT, HUMIDIFIER, AIR_PURIFIER, WATER_SOFTENER, SUMP_PUMP, WELL_PUMP, SEPTIC_PUMP, BACKFLOW_PREVENTER, ELECTRICAL_PANEL, GENERATOR, EV_CHARGER, GARAGE_DOOR_OPENER, POOL_PUMP, POOL_HEATER, REFRIGERATION, ICE_MACHINE, OTHER.
minAgeYearsquerynumberNo0–100.
memberOnlyqueryenumNotrue: active members only. One of true, false.
limitqueryintegerNoPage size, 1–200. Default 50.
offsetqueryintegerNoRows to skip; the answer's total counts every match. Default 0.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/replacements" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
totalinteger
itemsarray of object
items[].kindenumOne of SERVICE_DUE, EQUIPMENT_REPLACEMENT, LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE.
items[].subjectTypeenum or nullWhat subjectId is: equipment or a quote. One of asset, quote.
items[].subjectIdstringThe asset or quote id; empty for the customer.
items[].likelihoodnumber0–1: how likely (replacement, lapse, late payment, acceptance). Always 1 for SERVICE_DUE.
items[].confidencenumber0–1: how much data stands behind it.
items[].levelenumOne of HIGH, MEDIUM, LOW.
items[].basisstring or nullSERVICE_DUE: BOOKED, MEMBERSHIP, CADENCE, INTERVAL, SEASONAL or ANNUAL. Replacement: REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE. Quote: its Q-n.
items[].dueDatestring or nullYyyy-mm-dd: service due, end of life, the next expected visit, 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
items[].phonestring or null
items[].emailstring or null
items[].assetIdstring
items[].assetNamestring
items[].manufacturerstring or null
items[].modelstring or null
items[].equipmentTypestring or null
items[].installYearinteger or null
items[].ageYearsnumber or null
items[].lifespanYearsinteger or null
items[].refrigerantTypestring or null
items[].conditionstring or null
items[].repairs24minteger
items[].repairCost24mCentsinteger
items[].propertyobject or null
items[].property.idstring
items[].property.namestring or null
items[].property.addressstring or null
items[].property.citystring or null

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 rhythm, lapsed membership, declined quotes, bad reviews), LATE_PAYMENT (payment history; needs full invoice access) or QUOTE_ACCEPTANCE (each open quote). Filter by likelihood (default 0.35) and level. Read-only.

Permissioncustomers.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolinsights_predictions (toolset customers)

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.
memberOnlyqueryenumNoOne of true, false.
limitqueryintegerNoPage size, 1–200. Default 50.
offsetqueryintegerNoRows to skip; the answer's total counts every match. Default 0.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/predictions?kind=LAPSE_RISK" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
totalinteger
itemsarray of object
items[].kindenumOne of SERVICE_DUE, EQUIPMENT_REPLACEMENT, LAPSE_RISK, LATE_PAYMENT, QUOTE_ACCEPTANCE.
items[].subjectTypeenum or nullWhat subjectId is: equipment or a quote. One of asset, quote.
items[].subjectIdstringThe asset or quote id; empty for the customer.
items[].likelihoodnumber0–1: how likely (replacement, lapse, late payment, acceptance). Always 1 for SERVICE_DUE.
items[].confidencenumber0–1: how much data stands behind it.
items[].levelenumOne of HIGH, MEDIUM, LOW.
items[].basisstring or nullSERVICE_DUE: BOOKED, MEMBERSHIP, CADENCE, INTERVAL, SEASONAL or ANNUAL. Replacement: REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE. Quote: its Q-n.
items[].dueDatestring or nullYyyy-mm-dd: service due, end of life, the next expected visit, 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, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_recompute (toolset customers)

Request body

FieldTypeRequiredDescription
allbooleanNoRecompute everyone, not only stale ones.
limitintegerNoCustomers per call (default 500). 1–2000.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/recompute" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"all":true,"limit":1}'

Response

200: the answer's fields
FieldTypeDescription
addedinteger
recomputedinteger
remaininginteger

The equipment lifespan table

GET /organizations/{organizationId}/insights/lifespans

Expected lifespan in years per equipment type: the typical figure and the organization's own where it set one. Used by the replacement predictions. Read-only.

Permissioncustomers.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolinsights_lifespans (toolset customers)

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/lifespans" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
equipmentTypestring
defaultYearsinteger
yearsinteger
overriddenboolean

Change equipment lifespans

PATCH /organizations/{organizationId}/insights/lifespans

Sets the organization's expected lifespan (years) for equipment types; years: null goes back to the typical figure. Every customer's insights are recomputed afterwards (in the background, or POST /insights/recompute). Returns the table.

Permissionsettings.manage (Owner, Admin)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_setLifespans (toolset customers)

Request body

FieldTypeRequiredDescription
entriesarray of objectYesUp to 26 items.
entries[].equipmentTypeenumYesOne of AC, HEAT_PUMP, FURNACE, BOILER, MINI_SPLIT, AIR_HANDLER, PACKAGE_UNIT, WATER_HEATER, TANKLESS_WATER_HEATER, THERMOSTAT, HUMIDIFIER, AIR_PURIFIER, WATER_SOFTENER, SUMP_PUMP, WELL_PUMP, SEPTIC_PUMP, BACKFLOW_PREVENTER, ELECTRICAL_PANEL, GENERATOR, EV_CHARGER, GARAGE_DOOR_OPENER, POOL_PUMP, POOL_HEATER, REFRIGERATION, ICE_MACHINE, OTHER.
entries[].yearsinteger or nullYes1–100.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/lifespans" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"entries":[{"equipmentType":"AC","years":1}]}'

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
equipmentTypestring
defaultYearsinteger
yearsinteger
overriddenboolean

Create service requests for many customers

POST /organizations/{organizationId}/insights/bulk/requests

From "Service due": creates one NEW service request (REQ-n) per customer at their primary property, with the predicted date as the preferred date and the reasons in the internal notes, for the office to schedule. Nothing is sent to the customer. One row per customer: CREATED, SKIPPED or FAILED with the reason. Emits request.created per request.

Permissionrequests.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_bulkRequests (toolset customers)

Request body

FieldTypeRequiredDescription
customerIdsarray of stringYesCustomer ids from GET /insights/service-due or /insights/replacements, at most 100. Up to 100 items.
descriptionstring or nullNoDefault: "Service due around <date>". Up to 2000 characters.
serviceTypeIdstring or nullNo

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/bulk/requests" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerIds":["customer_id"]}'

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

Create replacement quotes for many customers

POST /organizations/{organizationId}/insights/bulk/quotes

From "Likely replacements": creates one DRAFT quote (Q-n) per customer titled for the unit most likely to need replacing, valid validDays (default 30), with the reasons in the internal notes and an empty "Replacement" option to price. Nothing is sent. One row per customer: CREATED, SKIPPED (no equipment) or FAILED. Emits quote.created per quote.

Permission: quotes.write (Owner, Admin, Dispatcher, Technician (quotes they sold)); risk write (OAuth scope servflo.write).

Permissionquotes.write
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_bulkQuotes (toolset customers)

Request body

FieldTypeRequiredDescription
customerIdsarray of stringYesCustomer ids from GET /insights/service-due or /insights/replacements, at most 100. Up to 100 items.
validDaysintegerNo1–365.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/bulk/quotes" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerIds":["customer_id"]}'

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

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, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolinsights_bulkTag (toolset customers)

Request body

FieldTypeRequiredDescription
customerIdsarray of stringYesCustomer ids from GET /insights/service-due or /insights/replacements, at most 100. Up to 100 items.
tagstringYesUp to 100 characters.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/insights/bulk/tag" \
  -H "Authorization: Bearer $SERVFLO_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