DevelopersAPI reference

Reports API

REST endpoints for reports in ServFlo: 18 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
Revenue reportGET /organizations/{organizationId}/reports/revenueread
Export the revenue report as CSVGET /organizations/{organizationId}/reports/revenue/exportread
Accounts receivable agingGET /organizations/{organizationId}/reports/ar-agingread
A customer's open invoices by ageGET /organizations/{organizationId}/reports/ar-aging/customers/{customerId}read
Export AR aging as CSVGET /organizations/{organizationId}/reports/ar-aging/exportread
Sales pipeline reportGET /organizations/{organizationId}/reports/pipelineread
Export the pipeline report as CSVGET /organizations/{organizationId}/reports/pipeline/exportread
In-home presentation resultsGET /organizations/{organizationId}/reports/presentationsread
Technician performance reportGET /organizations/{organizationId}/reports/techniciansread
Export technician performance as CSVGET /organizations/{organizationId}/reports/technicians/exportread
Job profitability reportGET /organizations/{organizationId}/reports/profitabilityread
Export job profitability as CSVGET /organizations/{organizationId}/reports/profitability/exportread
Memberships reportGET /organizations/{organizationId}/reports/membershipsread
Export the memberships report as CSVGET /organizations/{organizationId}/reports/memberships/exportread
Inventory reportGET /organizations/{organizationId}/reports/inventoryread
Export the inventory report as CSVGET /organizations/{organizationId}/reports/inventory/exportread
Payroll hours reportGET /organizations/{organizationId}/reports/payrollread
Export payroll hours as CSVGET /organizations/{organizationId}/reports/payroll/exportread

Revenue report

GET /organizations/{organizationId}/reports/revenue

Invoiced against collected over a date range, in day / week / month buckets, with the previous period of the same length for comparison. Invoiced = issued invoices (not drafts or cancelled) on the day they were created, tax included; collected = payments by their date, net of refunds; tips are reported apart and are not revenue. Breakdowns by service type, technician (the job's lead), lead source and customer type, with average ticket per invoice. Filters narrow everything; businessUnitId narrows to one unit (the invoice's) and byBusinessUnit gives each unit's own numbers. Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_revenue (toolset reports, in the default set)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
leadSourceIdquerystringNoOnly customers from this lead source (GET /lead-sources).
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the invoice's unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/revenue?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
range.granularityenumOne of day, week, month.
previousRangeobject
previousRange.fromstring
previousRange.tostring
totalsobject
totals.invoicedCentsnumberInteger cents.
totals.invoiceCountinteger
totals.collectedCentsnumberInteger cents.
totals.tipsCentsnumberInteger cents.
totals.feesCentsnumberOnline-payment fees the business paid on what was collected (Stripe's processing fees plus any ServFlo fee); Collected stays gross.
totals.averageTicketCentsnumberInteger cents.
previousTotalsobject
previousTotals.invoicedCentsnumberInteger cents.
previousTotals.invoiceCountinteger
previousTotals.collectedCentsnumberInteger cents.
previousTotals.tipsCentsnumberInteger cents.
previousTotals.feesCentsnumberOnline-payment fees the business paid on what was collected (Stripe's processing fees plus any ServFlo fee); Collected stays gross.
previousTotals.averageTicketCentsnumberInteger cents.
changesobject
changes.invoicedCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.collectedCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.averageTicketCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.tipsCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.invoiceCountnumber or nullPercent change from the previous period; null when the previous period was 0.
seriesarray of object
series[].keystringThe bucket's first day (Monday for weeks, the 1st for months).
series[].fromstring
series[].tostring
series[].invoicedCentsnumberInteger cents.
series[].invoiceCountinteger
series[].collectedCentsnumberInteger cents.
series[].tipsCentsnumberInteger cents.
series[].feesCentsnumberInteger cents.
series[].previousInvoicedCentsnumber or nullInteger cents.
series[].previousCollectedCentsnumber or nullInteger cents.
byServiceTypearray of object
byServiceType[].idstring or null
byServiceType[].namestring
byServiceType[].colorstring or null
byServiceType[].invoiceCountinteger
byServiceType[].invoicedCentsnumberInteger cents.
byServiceType[].averageTicketCentsnumberInteger cents.
byServiceType[].sharePercentnumber
byTechnicianarray of object
byTechnician[].idstring or null
byTechnician[].namestring
byTechnician[].colorstring or null
byTechnician[].invoiceCountinteger
byTechnician[].invoicedCentsnumberInteger cents.
byTechnician[].averageTicketCentsnumberInteger cents.
byTechnician[].sharePercentnumber
byLeadSourcearray of object
byLeadSource[].idstring or null
byLeadSource[].namestring
byLeadSource[].colorstring or null
byLeadSource[].invoiceCountinteger
byLeadSource[].invoicedCentsnumberInteger cents.
byLeadSource[].averageTicketCentsnumberInteger cents.
byLeadSource[].sharePercentnumber
byCustomerTypearray of object
byCustomerType[].idstring or null
byCustomerType[].namestring
byCustomerType[].colorstring or null
byCustomerType[].invoiceCountinteger
byCustomerType[].invoicedCentsnumberInteger cents.
byCustomerType[].averageTicketCentsnumberInteger cents.
byCustomerType[].sharePercentnumber
byBusinessUnitarray of objectEach business unit's own numbers: every active unit (zeros included; with a unit filter only that unit), then "No unit" (invoices, and payments, without one) when it has any. Empty for a business without units.
byBusinessUnit[].idstring or nullThe unit's id; null = the "No unit" row.
byBusinessUnit[].namestring
byBusinessUnit[].invoiceCountinteger
byBusinessUnit[].invoicedCentsnumberInteger cents.
byBusinessUnit[].collectedCentsnumberPayments by their date on this unit's invoices, net of refunds, tips apart.
byBusinessUnit[].tipsCentsnumberInteger cents.
byBusinessUnit[].averageTicketCentsnumberInteger cents.
byBusinessUnit[].sharePercentnumberShare of the report's invoiced total.

Export the revenue report as CSV

GET /organizations/{organizationId}/reports/revenue/export

The revenue report's table as CSV: table = series (one row per bucket, the default) or a breakdown (serviceType, technician, leadSource, customerType, businessUnit). Same inputs as GET /reports/revenue. Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_revenueExport (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
leadSourceIdquerystringNoOnly customers from this lead source (GET /lead-sources).
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the invoice's unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.
tablequeryenumNoWhich table: series, or a breakdown (businessUnit = per business unit). One of series, serviceType, technician, leadSource, customerType, businessUnit. Default series.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/revenue/export?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

Accounts receivable aging

GET /organizations/{organizationId}/reports/ar-aging

Open balances today (sent and overdue invoices, total less payments) by days past due: current (not yet due), 1–30, 31–60, 61–90 and 90+, in total and per customer (largest balance first). Days count from the due date, or from the issue date when there is none. Drill into a customer with GET /reports/ar-aging/customers/{customerId}. Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_arAging (toolset reports)

Parameters

NameInTypeRequiredDescription
todayquerystringNoYour today (YYYY-MM-DD), accepted within a day of the server's; defaults to the server's (UTC).
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the invoice's unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/ar-aging" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
asOfstring
totalsobject
totals.currentnumberNot yet due.
totals.days1to30numberInteger cents.
totals.days31to60numberInteger cents.
totals.days61to90numberInteger cents.
totals.days90plusnumberInteger cents.
totals.totalCentsnumberInteger cents.
totals.invoiceCountinteger
totals.customerCountinteger
overduePercentnumberShare of the open balance that is past due.
customersarray of object
customers[].customerIdstring
customers[].namestring
customers[].typeenumOne of RESIDENTIAL, COMMERCIAL.
customers[].invoiceCountinteger
customers[].oldestDaysPastDueinteger
customers[].currentnumberNot yet due.
customers[].days1to30numberInteger cents.
customers[].days31to60numberInteger cents.
customers[].days61to90numberInteger cents.
customers[].days90plusnumberInteger cents.
customers[].totalCentsnumberInteger cents.

A customer's open invoices by age

GET /organizations/{organizationId}/reports/ar-aging/customers/{customerId}

The AR aging drill-down: one customer's open invoices (identifier, issue and due dates, days past due, bucket, total, paid, balance), oldest due first. Get customer ids from GET /reports/ar-aging. Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_arAgingCustomer (toolset reports)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes
todayquerystringNoYour today (YYYY-MM-DD), accepted within a day of the server's; defaults to the server's (UTC).
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Only the customer's invoices of that unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/ar-aging/customers/{customerId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
customerIdstring
namestring
asOfstring
invoicesarray of object
invoices[].idstring
invoices[].identifierstring
invoices[].statusenumOne of SENT, OVERDUE.
invoices[].issuedOnstring
invoices[].dueDatestring or null
invoices[].daysPastDueinteger
invoices[].bucketenumOne of current, days1to30, days31to60, days61to90, days90plus.
invoices[].totalCentsnumberInteger cents.
invoices[].paidCentsnumberInteger cents.
invoices[].balanceCentsnumberInteger cents.

Export AR aging as CSV

GET /organizations/{organizationId}/reports/ar-aging/export

The AR aging report per customer as CSV (one row per customer, one column per bucket). Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_arAgingExport (toolset reports)

Parameters

NameInTypeRequiredDescription
todayquerystringNoYour today (YYYY-MM-DD), accepted within a day of the server's; defaults to the server's (UTC).
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the invoice's unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/ar-aging/export" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

Sales pipeline report

GET /organizations/{organizationId}/reports/pipeline

Requests → quotes → approved → converted for work that came in during the range, close rate (approved ÷ sent), average quote value (approved total, else the largest option's default lines, before tax), days from sent to approved (average and median), per salesperson (the quote's sold-by technician) and per lead source (new customers, requests, quotes, approved, revenue invoiced, and ad spend for the lead sources ads create: Google Ads, Facebook / Instagram, Google Local Services), with the previous period. technicianId filters by sold-by. Read-only.

Permissionreports.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_pipeline (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
leadSourceIdquerystringNoOnly customers from this lead source (GET /lead-sources).
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/pipeline?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
range.granularityenumOne of day, week, month.
previousRangeobject
previousRange.fromstring
previousRange.tostring
totalsobject
totals.requestsinteger
totals.requestsConvertedinteger
totals.quotesinteger
totals.sentinteger
totals.approvedinteger
totals.convertedinteger
totals.closeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
totals.averageQuoteCentsnumberInteger cents.
totals.approvedValueCentsnumberInteger cents.
totals.timeToApproveobject
totals.timeToApprove.averageDaysnumber or null
totals.timeToApprove.medianDaysnumber or null
totals.timeToApprove.countinteger
previousTotalsobject
previousTotals.requestsinteger
previousTotals.requestsConvertedinteger
previousTotals.quotesinteger
previousTotals.sentinteger
previousTotals.approvedinteger
previousTotals.convertedinteger
previousTotals.closeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
previousTotals.averageQuoteCentsnumberInteger cents.
previousTotals.approvedValueCentsnumberInteger cents.
previousTotals.timeToApproveobject
previousTotals.timeToApprove.averageDaysnumber or null
previousTotals.timeToApprove.medianDaysnumber or null
previousTotals.timeToApprove.countinteger
changesobject
changes.quotesnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.approvedValueCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.averageQuoteCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.closeRatenumber or nullChange in percentage points.
seriesarray of object
series[].keystring
series[].fromstring
series[].tostring
series[].quotesCreatednumber
series[].quotesSentnumber
series[].quotesApprovednumber
series[].approvedValueCentsnumberInteger cents.
bySalespersonarray of object
bySalesperson[].technicianIdstring or null
bySalesperson[].namestring
bySalesperson[].colorstring or null
bySalesperson[].quotesinteger
bySalesperson[].sentinteger
bySalesperson[].approvedinteger
bySalesperson[].closeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
bySalesperson[].approvedValueCentsnumberInteger cents.
bySalesperson[].averageQuoteCentsnumberInteger cents.
byLeadSourcearray of object
byLeadSource[].leadSourceIdstring or null
byLeadSource[].namestring
byLeadSource[].newCustomersinteger
byLeadSource[].requestsinteger
byLeadSource[].quotesinteger
byLeadSource[].approvedinteger
byLeadSource[].closeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
byLeadSource[].revenueCentsnumberInteger cents.
byLeadSource[].revenuePerCustomerCentsnumberInteger cents.
byLeadSource[].adSpendCentsnumber or nullAd spend in the range for an ad platform's lead source; null for other sources.
byLeadSource[].costPerCustomerCentsnumber or nullAd spend ÷ new customers; null without ad spend or new customers.

Export the pipeline report as CSV

GET /organizations/{organizationId}/reports/pipeline/export

The pipeline report as CSV: table = series (default), salesperson or leadSource. Same inputs as GET /reports/pipeline. Read-only.

Permissionreports.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_pipelineExport (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
leadSourceIdquerystringNoOnly customers from this lead source (GET /lead-sources).
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
tablequeryenumNoOne of series, salesperson, leadSource. Default series.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/pipeline/export?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

In-home presentation results

GET /organizations/{organizationId}/reports/presentations

The pipeline report's presenter block: in-home presentations started in the range — presented, won and close rate, the membership attach rate on wins, average seconds per step, which tier won on good / better / best quotes, and the same per presenter (technician, else the staff member). A presentation counts once per quote and presenter (the latest); one still open whose quote was approved later counts as won. businessUnitId uses the quote's unit, technicianId the presenter. Read-only.

Permissionreports.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_presentations (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
technicianIdquerystringNoOnly presentations by this technician.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the quote's unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/presentations?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
presentedinteger
woninteger
closeRatenumber or null
membershipAttachRatenumber or null
averageSecondsByStepobject
chosenTierobject
chosenTier.GOODinteger
chosenTier.BETTERinteger
chosenTier.BESTinteger
chosenTier.OTHERinteger
byPresenterarray of object
byPresenter[].presenterKeystring
byPresenter[].namestring
byPresenter[].presentedinteger
byPresenter[].woninteger
byPresenter[].closeRatenumber or null
byPresenter[].averageMinutesnumber or null

Technician performance report

GET /organizations/{organizationId}/reports/technicians

Per technician over the range: visits and jobs completed, revenue produced (issued invoices of jobs they lead) and average ticket, sold amount and close rate (quotes they sold), hours worked (time entries: shift less breaks, else job and travel time) and revenue per hour, on-time arrival (arrived within 15 minutes of the scheduled start, in the property's timezone, else timezone) and callbacks (a completed job at the same property for the same service type within 30 days of an earlier one, charged to the earlier job's technician; member visits and recurring jobs excluded). With the previous period. Technicians themselves cannot read reports. Read-only.

Permissionreports.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_technicians (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the job's unit: visits, jobs and revenue of that unit's jobs, quotes of that unit, and hours = job and travel time on that unit's jobs; lists that unit's technicians. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/technicians?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
range.granularityenumOne of day, week, month.
previousRangeobject
previousRange.fromstring
previousRange.tostring
toleranceMinutesinteger
callbackWindowDaysinteger
totalsobject
totals.visitsCompletedinteger
totals.jobsCompletedinteger
totals.invoiceCountinteger
totals.revenueCentsnumberInteger cents.
totals.quotesSentinteger
totals.quotesApprovedinteger
totals.soldCentsnumberInteger cents.
totals.minutesWorkednumber
totals.arrivalsinteger
totals.onTimeArrivalsinteger
totals.callbacksinteger
totals.averageTicketCentsnumberInteger cents.
totals.closeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
totals.hoursWorkednumber
totals.revenuePerHourCentsnumber or nullInteger cents.
totals.onTimeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
totals.callbackRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
previousTotalsobject
previousTotals.visitsCompletedinteger
previousTotals.jobsCompletedinteger
previousTotals.invoiceCountinteger
previousTotals.revenueCentsnumberInteger cents.
previousTotals.quotesSentinteger
previousTotals.quotesApprovedinteger
previousTotals.soldCentsnumberInteger cents.
previousTotals.minutesWorkednumber
previousTotals.arrivalsinteger
previousTotals.onTimeArrivalsinteger
previousTotals.callbacksinteger
previousTotals.averageTicketCentsnumberInteger cents.
previousTotals.closeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
previousTotals.hoursWorkednumber
previousTotals.revenuePerHourCentsnumber or nullInteger cents.
previousTotals.onTimeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
previousTotals.callbackRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
changesobject
changes.revenueCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.jobsCompletednumber or nullPercent change from the previous period; null when the previous period was 0.
changes.hoursWorkednumber or nullPercent change from the previous period; null when the previous period was 0.
techniciansarray of object
technicians[].technicianIdstring
technicians[].namestring
technicians[].colorstring or null
technicians[].previousRevenueCentsnumberInteger cents.
technicians[].visitsCompletedinteger
technicians[].jobsCompletedinteger
technicians[].invoiceCountinteger
technicians[].revenueCentsnumberInteger cents.
technicians[].quotesSentinteger
technicians[].quotesApprovedinteger
technicians[].soldCentsnumberInteger cents.
technicians[].minutesWorkednumber
technicians[].arrivalsinteger
technicians[].onTimeArrivalsinteger
technicians[].callbacksinteger
technicians[].averageTicketCentsnumberInteger cents.
technicians[].closeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
technicians[].hoursWorkednumber
technicians[].revenuePerHourCentsnumber or nullInteger cents.
technicians[].onTimeRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
technicians[].callbackRatenumber or nullPercent with one decimal; null when there is nothing to divide by.

Export technician performance as CSV

GET /organizations/{organizationId}/reports/technicians/export

The technician performance report as CSV, one row per technician. Read-only.

Permissionreports.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_techniciansExport (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the job's unit: visits, jobs and revenue of that unit's jobs, quotes of that unit, and hours = job and travel time on that unit's jobs; lists that unit's technicians. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/technicians/export?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

Job profitability report

GET /organizations/{organizationId}/reports/profitability

Margin of the jobs completed in the range (job costing: invoiced revenue before tax less labour at each technician's hourly cost, materials at their cost snapshot, job purchase orders and expenses), per job, per service type and per technician, plus the 10 lowest-margin jobs and the previous period. Owners and admins only (costing.read). Read-only.

Permissioncosting.read (Owner, Admin)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_profitability (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
leadSourceIdquerystringNoOnly customers from this lead source (GET /lead-sources).
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the job's unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/profitability?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
range.granularityenumOne of day, week, month.
previousRangeobject
previousRange.fromstring
previousRange.tostring
totalsobject
totals.jobsinteger
totals.revenueCentsnumberInteger cents.
totals.costCentsnumberInteger cents.
totals.marginCentsnumberInteger cents.
totals.marginPercentnumber or null
previousTotalsobject
previousTotals.jobsinteger
previousTotals.revenueCentsnumberInteger cents.
previousTotals.costCentsnumberInteger cents.
previousTotals.marginCentsnumberInteger cents.
previousTotals.marginPercentnumber or null
changesobject
changes.revenueCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.marginCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
byServiceTypearray of object
byServiceType[].idstring or null
byServiceType[].namestring
byServiceType[].colorstring or null
byServiceType[].jobsinteger
byServiceType[].revenueCentsnumberInteger cents.
byServiceType[].costCentsnumberInteger cents.
byServiceType[].marginCentsnumberInteger cents.
byServiceType[].marginPercentnumber or null
byTechnicianarray of object
byTechnician[].idstring or null
byTechnician[].namestring
byTechnician[].colorstring or null
byTechnician[].jobsinteger
byTechnician[].revenueCentsnumberInteger cents.
byTechnician[].costCentsnumberInteger cents.
byTechnician[].marginCentsnumberInteger cents.
byTechnician[].marginPercentnumber or null
usesBusinessUnitsbooleanThe business has business units.
byBusinessUnitarray of objectEach business unit's jobs, revenue, cost and margin (the job's unit): every active unit, then "No unit" (id null). Empty for a business without units; with a unit filter only that unit.
byBusinessUnit[].idstring or null
byBusinessUnit[].namestring
byBusinessUnit[].colorstring or null
byBusinessUnit[].jobsinteger
byBusinessUnit[].revenueCentsnumberInteger cents.
byBusinessUnit[].costCentsnumberInteger cents.
byBusinessUnit[].marginCentsnumberInteger cents.
byBusinessUnit[].marginPercentnumber or null
lowestMarginarray of object
lowestMargin[].jobIdstring
lowestMargin[].identifierstring
lowestMargin[].customerNamestring
lowestMargin[].completedOnstring
lowestMargin[].technicianIdstring or null
lowestMargin[].technicianNamestring
lowestMargin[].serviceTypeIdstring or null
lowestMargin[].serviceTypeNamestring
lowestMargin[].businessUnitIdstring or null
lowestMargin[].businessUnitNamestring or nullNull when the job has no business unit.
lowestMargin[].revenueCentsnumberInteger cents.
lowestMargin[].costCentsnumberInteger cents.
lowestMargin[].marginCentsnumberInteger cents.
lowestMargin[].marginPercentnumber or null
jobsarray of object
jobs[].jobIdstring
jobs[].identifierstring
jobs[].customerNamestring
jobs[].completedOnstring
jobs[].technicianIdstring or null
jobs[].technicianNamestring
jobs[].serviceTypeIdstring or null
jobs[].serviceTypeNamestring
jobs[].businessUnitIdstring or null
jobs[].businessUnitNamestring or nullNull when the job has no business unit.
jobs[].revenueCentsnumberInteger cents.
jobs[].costCentsnumberInteger cents.
jobs[].marginCentsnumberInteger cents.
jobs[].marginPercentnumber or null

Export job profitability as CSV

GET /organizations/{organizationId}/reports/profitability/export

The job profitability report as CSV, one row per completed job with revenue, cost and margin. Read-only.

Permissioncosting.read (Owner, Admin)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_profitabilityExport (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
serviceTypeIdquerystringNoOnly jobs of this service type (GET /service-types).
leadSourceIdquerystringNoOnly customers from this lead source (GET /lead-sources).
customerTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the job's unit. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/profitability/export?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

Memberships report

GET /organizations/{organizationId}/reports/memberships

Active members and monthly recurring revenue (MRR) at the end of each bucket, sign-ups, cancellations and expiries (churn rate = cancelled and expired ÷ the members at the start plus sign-ups), members per plan, renewals due in the next 60 days from today, and the average ticket of members against non-members (membership fee invoices left out). With the previous period. Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_memberships (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
todayquerystringNoYour today (YYYY-MM-DD), accepted within a day of the server's; defaults to the server's (UTC).
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the membership's unit (members, MRR, churn, renewals, plans) and the invoice's unit for the member / non-member average ticket. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/memberships?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
range.granularityenumOne of day, week, month.
previousRangeobject
previousRange.fromstring
previousRange.tostring
totalsobject
totals.activeMembersinteger
totals.mrrCentsnumberInteger cents.
totals.newMembersinteger
totals.cancelledinteger
totals.expiredinteger
totals.churnRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
previousTotalsobject
previousTotals.activeMembersinteger
previousTotals.mrrCentsnumberInteger cents.
previousTotals.newMembersinteger
previousTotals.cancelledinteger
previousTotals.expiredinteger
previousTotals.churnRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
changesobject
changes.activeMembersnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.mrrCentsnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.newMembersnumber or nullPercent change from the previous period; null when the previous period was 0.
seriesarray of object
series[].activeMembersinteger
series[].mrrCentsnumberInteger cents.
series[].newMembersinteger
series[].cancelledinteger
series[].expiredinteger
series[].churnRatenumber or nullPercent with one decimal; null when there is nothing to divide by.
series[].keystring
series[].fromstring
series[].tostring
plansarray of object
plans[].planIdstring
plans[].namestring
plans[].membersinteger
plans[].mrrCentsnumberInteger cents.
renewalsDuearray of object
renewalsDue[].membershipIdstring
renewalsDue[].identifierstring
renewalsDue[].customerIdstring
renewalsDue[].customerNamestring
renewalsDue[].planNamestring
renewalsDue[].endDatestring
renewalsDue[].autoRenewboolean
renewalsDue[].priceCentsnumberInteger cents.
averageTicketobject
averageTicket.memberCentsnumberInteger cents.
averageTicket.memberInvoicesinteger
averageTicket.nonMemberCentsnumberInteger cents.
averageTicket.nonMemberInvoicesinteger

Export the memberships report as CSV

GET /organizations/{organizationId}/reports/memberships/export

Members, MRR, sign-ups, cancellations and churn per bucket as CSV. Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_membershipsExport (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
todayquerystringNoYour today (YYYY-MM-DD), accepted within a day of the server's; defaults to the server's (UTC).
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses the membership's unit (members, MRR, churn, renewals, plans) and the invoice's unit for the member / non-member average ticket. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/memberships/export?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

Inventory report

GET /organizations/{organizationId}/reports/inventory

Stock value at cost by location (now; cost needs costing.read), quantity used by item over the range (job use less returns, with its cost) and the items at or below their reorder point with a suggested order. With the previous period's usage. Read-only.

Permissionreports.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_inventory (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/inventory?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
range.granularityenumOne of day, week, month.
previousRangeobject
previousRange.fromstring
previousRange.tostring
totalsobject
totals.quantityUsednumber
totals.costCentsnumberInteger cents.
totals.stockValueCentsnumberInteger cents.
totals.lowStockCountinteger
previousTotalsobject
previousTotals.quantityUsednumber
previousTotals.costCentsnumberInteger cents.
changesobject
changes.quantityUsednumber or nullPercent change from the previous period; null when the previous period was 0.
seriesarray of object
series[].keystring
series[].fromstring
series[].tostring
series[].quantityUsednumber
series[].costCentsnumberInteger cents.
locationsarray of object
locations[].locationIdstring
locations[].namestring
locations[].kindenumOne of WAREHOUSE, TRUCK.
locations[].itemsinteger
locations[].unitsnumber
locations[].stockValueCentsnumberInteger cents.
usagearray of object
usage[].itemIdstring
usage[].namestring
usage[].unitstring
usage[].quantityUsednumber
usage[].costCentsnumberInteger cents.
lowStockarray of object
lowStock[].itemIdstring
lowStock[].namestring
lowStock[].unitstring
lowStock[].locationIdstring
lowStock[].locationNamestring
lowStock[].onHandnumber
lowStock[].reorderPointnumber
lowStock[].suggestedQuantitynumber

Export the inventory report as CSV

GET /organizations/{organizationId}/reports/inventory/export

The inventory report as CSV: table = usage (default), locations or lowStock. Cost columns only for costing.read. Read-only.

Permissionreports.read (Owner, Admin, Dispatcher, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_inventoryExport (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
tablequeryenumNoOne of usage, locations, lowStock. Default usage.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/inventory/export?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

Payroll hours report

GET /organizations/{organizationId}/reports/payroll

Hours by person by week (Monday–Sunday, whole weeks around the range): paid time per day (shift less breaks, else job and travel time), regular up to 40 hours a week and overtime beyond (US FLSA weekly rule; no daily overtime), approved against pending (open or submitted; rejected time left out). Pay (costCents: regular × hourly pay + overtime × 1.5) only for costing.read. Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_payroll (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses each person's home unit (their technician's); people who are not technicians have none. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/payroll?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
rangeobject
range.fromstring
range.tostring
range.timezonestring
range.granularityweek
weeksobjectThe whole weeks covered (Monday to Sunday).
weeks.fromstring
weeks.tostring
previousRangeobject
previousRange.fromstring
previousRange.tostring
overtimeThresholdMinutesinteger
usesBusinessUnitsbooleanThe business has business units.
totalsobject
totals.peopleinteger
totals.paidMinutesnumber
totals.regularMinutesnumber
totals.overtimeMinutesnumber
totals.approvedMinutesnumber
totals.pendingMinutesnumber
totals.costCentsnumberInteger cents.
previousTotalsobject
previousTotals.peopleinteger
previousTotals.paidMinutesnumber
previousTotals.regularMinutesnumber
previousTotals.overtimeMinutesnumber
previousTotals.approvedMinutesnumber
previousTotals.pendingMinutesnumber
previousTotals.costCentsnumberInteger cents.
changesobject
changes.paidMinutesnumber or nullPercent change from the previous period; null when the previous period was 0.
changes.overtimeMinutesnumber or nullPercent change from the previous period; null when the previous period was 0.
seriesarray of object
series[].keystring
series[].regularMinutesnumber
series[].overtimeMinutesnumber
series[].approvedMinutesnumber
rowsarray of object
rows[].userIdstring
rows[].technicianIdstring or null
rows[].namestring
rows[].businessUnitIdstring or nullThe technician's home business unit; null = none (or not a technician).
rows[].businessUnitNamestring or null
rows[].weekStartstring
rows[].paidMinutesnumber
rows[].regularMinutesnumber
rows[].overtimeMinutesnumber
rows[].approvedMinutesnumber
rows[].pendingMinutesnumber
rows[].submittedMinutesnumber
rows[].statusenumOne of APPROVED, SUBMITTED, OPEN.
rows[].costCentsnumber or nullInteger cents.

Export payroll hours as CSV

GET /organizations/{organizationId}/reports/payroll/export

Hours by person by week as CSV (decimal hours: total, regular, overtime, approved, pending, status; pay only for costing.read). Read-only.

Permissionreports.financial (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolreports_payrollExport (toolset reports)

Parameters

NameInTypeRequiredDescription
fromquerystringYesFirst day of the range, YYYY-MM-DD (business calendar).
toquerystringYesLast day of the range (inclusive), at most 731 days after from.
timezonequerystringNoOverride of the IANA timezone the business's days are counted in (timestamps such as invoice creation become dates in it), e.g. America/Chicago. Default: the organization's timezone (Settings → General). Up to 100 characters.
granularityqueryenumNoChart buckets: day, week (Monday) or month. Default: day up to 31 days, week up to 120, else month. One of day, week, month.
compareFromquerystringNoFirst day of the comparison period (with compareTo). Default by the range's shape: month / quarter / year to date → the same days of the previous month / quarter / last year; whole months → the months before; else the same number of days just before.
compareToquerystringNoLast day of the comparison period.
technicianIdquerystringNoOnly work led (or quotes sold) by this technician (GET /technicians).
businessUnitIdquerystringNoOnly one business unit (ids from GET /business-units), or "none" for records without a unit. Uses each person's home unit (their technician's); people who are not technicians have none. Omit for the whole business (a business without units never needs it). Up to 100 characters.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/reports/payroll/export?from=2026-11-03&to=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
fileNamestring
csvstringComma-separated, CRLF line ends, header first; money as decimals.
countinteger

On this page