DevelopersAPI reference

Sales presenter API

REST endpoints for sales presenter in ServFlo: 9 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
List presentation templatesGET /organizations/{organizationId}/presentation-templatesread
Create a presentation templatePOST /organizations/{organizationId}/presentation-templateswrite
Change a presentation templatePATCH /organizations/{organizationId}/presentation-templates/{templateId}write
Delete a presentation templateDELETE /organizations/{organizationId}/presentation-templates/{templateId}sensitive
Quotes to present for a jobGET /organizations/{organizationId}/jobs/{jobId}/presentable-quotesread
A quote's in-home presentationGET /organizations/{organizationId}/quotes/{quoteId}/presentationread
Start presenting a quotePOST /organizations/{organizationId}/quotes/{quoteId}/presentationswrite
Report presentation progressPATCH /organizations/{organizationId}/quotes/{quoteId}/presentations/{presentationId}write
The customer approves in the presentationPOST /organizations/{organizationId}/quotes/{quoteId}/presentations/{presentationId}/completesensitive

List presentation templates

GET /organizations/{organizationId}/presentation-templates

The business's in-home presentation templates (Settings → Sales presenter): sections in order with their copy and images, company story, trust badges, reviews on/off and the membership add-on; one may be the default and others belong to business units. With none, the built-in template is used. Read-only.

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

Permissionquotes.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolpresentationTemplates_list (toolset sales)

Example

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

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstring
items[].namestring
items[].businessUnitIdstring or null
items[].businessUnitobject or null
items[].businessUnit.idstring
items[].businessUnit.namestring
items[].isDefaultboolean
items[].contentobject
items[].content.sectionsarray of object
items[].content.companyStorystring or null
items[].content.trustBadgesarray of object
items[].content.showReviewsboolean
items[].content.membershipPlanIdstring or null
items[].createdAtstring (date-time)
items[].updatedAtstring (date-time)

Create a presentation template

POST /organizations/{organizationId}/presentation-templates

A template for the in-home presentation. The first one for the whole business becomes the default. 409 on a duplicate name. Customer-visible on the next presentation.

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

Request body

FieldTypeRequiredDescription
namestringYesUp to 120 characters.
businessUnitIdstring or nullNoA business unit whose quotes use this template; null = the whole business.
isDefaultbooleanNoThe business's default template (one at most).
contentobjectNoSections in order (INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL; APPROVAL stays on) with title, copy and image; the company story; trust badges (licensed, insured…); whether to show reviews; the membership plan offered as an add-on.
content.sectionsarray of objectYesUp to 5 items.
content.sections[].stepenumYesOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
content.sections[].enabledbooleanNoDefault true.
content.sections[].titlestring or nullNoUp to 120 characters.
content.sections[].bodystring or nullNoUp to 4000 characters.
content.sections[].imageUrlstring or nullNoUp to 2000 characters.
content.companyStorystring or nullNoUp to 4000 characters.
content.trustBadgesarray of objectNoUp to 8 items. Default [].
content.trustBadges[].labelstringYesUp to 80 characters.
content.trustBadges[].detailstring or nullNoUp to 200 characters.
content.showReviewsbooleanNoDefault true.
content.membershipPlanIdstring or nullNo

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/presentation-templates" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield"}'

Response

201: the answer's fields
FieldTypeDescription
idstring
namestring
businessUnitIdstring or null
businessUnitobject or null
businessUnit.idstring
businessUnit.namestring
isDefaultboolean
contentobject
content.sectionsarray of object
content.sections[].stepenumOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
content.sections[].enabledboolean
content.sections[].titlestring or null
content.sections[].bodystring or null
content.sections[].imageUrlstring or null
content.companyStorystring or null
content.trustBadgesarray of object
content.trustBadges[].labelstring
content.trustBadges[].detailstring or null
content.showReviewsboolean
content.membershipPlanIdstring or null
createdAtstring (date-time)
updatedAtstring (date-time)

Change a presentation template

PATCH /organizations/{organizationId}/presentation-templates/{templateId}

Change a template's sections, copy, images, badges, reviews switch, membership add-on, unit or default flag. Customer-visible on the next presentation.

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

Parameters

NameInTypeRequiredDescription
templateIdpathstringYes

Request body

FieldTypeRequiredDescription
namestringNoUp to 120 characters.
businessUnitIdstring or nullNoA business unit whose quotes use this template; null = the whole business.
isDefaultbooleanNoThe business's default template (one at most).
contentobjectNoSections in order (INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL; APPROVAL stays on) with title, copy and image; the company story; trust badges (licensed, insured…); whether to show reviews; the membership plan offered as an add-on.
content.sectionsarray of objectYesUp to 5 items.
content.sections[].stepenumYesOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
content.sections[].enabledbooleanNoDefault true.
content.sections[].titlestring or nullNoUp to 120 characters.
content.sections[].bodystring or nullNoUp to 4000 characters.
content.sections[].imageUrlstring or nullNoUp to 2000 characters.
content.companyStorystring or nullNoUp to 4000 characters.
content.trustBadgesarray of objectNoUp to 8 items. Default [].
content.trustBadges[].labelstringYesUp to 80 characters.
content.trustBadges[].detailstring or nullNoUp to 200 characters.
content.showReviewsbooleanNoDefault true.
content.membershipPlanIdstring or nullNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/presentation-templates/{templateId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","businessUnitId":"businessUnit_id","isDefault":true}'

Response

200: the answer's fields
FieldTypeDescription
idstring
namestring
businessUnitIdstring or null
businessUnitobject or null
businessUnit.idstring
businessUnit.namestring
isDefaultboolean
contentobject
content.sectionsarray of object
content.sections[].stepenumOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
content.sections[].enabledboolean
content.sections[].titlestring or null
content.sections[].bodystring or null
content.sections[].imageUrlstring or null
content.companyStorystring or null
content.trustBadgesarray of object
content.trustBadges[].labelstring
content.trustBadges[].detailstring or null
content.showReviewsboolean
content.membershipPlanIdstring or null
createdAtstring (date-time)
updatedAtstring (date-time)

Delete a presentation template

DELETE /organizations/{organizationId}/presentation-templates/{templateId}

Destructive: removes the template; its quotes fall back to the default (or the built-in one). Past presentations keep their analytics.

Permissionpresentations.manage (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolpresentationTemplates_delete (toolset sales)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
templateIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/presentation-templates/{templateId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

Quotes to present for a job

GET /organizations/{organizationId}/jobs/{jobId}/presentable-quotes

The job's customer's quotes that can still be presented (draft, sent, changes requested, expired), newest first; a technician sees the ones they sold. Pick one, then GET /quotes/{quoteId}/presentation?jobId=… Read-only.

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

Permissionquotes.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolpresentations_forJob (toolset sales)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/presentable-quotes" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
jobIdstring
customerIdstring
itemsarray of object
items[].idstring
items[].identifierstring
items[].titlestring or null
items[].statusstring
items[].createdAtstring (date-time)
items[].optionCountinteger

A quote's in-home presentation

GET /organizations/{organizationId}/quotes/{quoteId}/presentation

Everything the tablet presentation shows for one quote: branding (the unit's), the template's steps and copy, reviews and trust badges, the job's photos and notes with the equipment's age and replacement outlook (pass jobId), the good / better / best options with images, features, warranty and prices (as a member with the add-on, and "as low as" per month when financing is on, with the disclosure), and the approval terms. A technician sees only quotes they sold. Read-only.

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

Permissionquotes.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolpresentations_get (toolset sales)

Parameters

NameInTypeRequiredDescription
quoteIdpathstringYes
jobIdquerystringNo

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/quotes/{quoteId}/presentation" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
quoteobject
quote.idstring
quote.identifierstring
quote.titlestring or null
quote.messagestring or null
quote.statusstring
quote.canApproveboolean
quote.publicTokenstring or nullFor the card deposit: /q/{token}.
quote.validUntilstring or null
quote.taxRatenumber
quote.depositPercentnumber or null
quote.depositCentsinteger or null
quote.businessUnitIdstring or null
quote.customerobject
quote.customer.idstring
quote.customer.namestring
quote.propertyobject or null
quote.property.idstring
quote.property.namestring or null
quote.property.addressstring or null
quote.property.citystring or null
brandingobject
branding.businessNamestring
branding.unitNamestring or null
branding.phonestring or null
branding.emailstring or null
branding.logostring or null
branding.footerstring or null
templateobject
template.idstring or null
template.namestring
template.sectionsarray of object
template.sections[].stepenumOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
template.sections[].enabledboolean
template.sections[].titlestring or null
template.sections[].bodystring or null
template.sections[].imageUrlstring or null
stepsarray of enumThe steps shown, in order (empty findings / financing are skipped).
introobject
intro.companyStorystring or null
intro.trustBadgesarray of object
intro.trustBadges[].labelstring
intro.trustBadges[].detailstring or null
intro.licenseTextstring or null
intro.reviewsarray of object
intro.reviews[].quotestring
intro.reviews[].authorstring
intro.reviews[].ratingnumber
intro.reviews[].sourceenumOne of GOOGLE, WEBSITE.
intro.ratingobject or null
intro.rating.averagenumber
intro.rating.countinteger
findingsobject
findings.jobobject or null
findings.job.idstring
findings.job.identifierstring
findings.job.servicestring or null
findings.job.scheduledDatestring
findings.job.notesstring or null
findings.job.completionNotesstring or null
findings.notesarray of object
findings.notes[].contentstring
findings.notes[].createdAtstring (date-time)
findings.photosarray of object
findings.photos[].idstring
findings.photos[].urlstring
findings.photos[].tagstring or null
findings.photos[].fileNamestring
findings.equipmentarray of object
findings.equipment[].assetIdstring
findings.equipment[].namestring
findings.equipment[].equipmentTypestring
findings.equipment[].installYearinteger or null
findings.equipment[].ageYearsnumber or null
findings.equipment[].lifespanYearsinteger
findings.equipment[].lifeUsednumber or null
findings.equipment[].conditionstring or null
findings.equipment[].outlookenumOne of REPLACE_NOW, PLAN, HEALTHY, UNKNOWN_AGE.
findings.equipment[].repairs24minteger
findings.equipment[].replaceBystring or null
optionsarray of object
options[].idstring
options[].namestring
options[].descriptionstring or null
options[].tierenum or nullOne of GOOD, BETTER, BEST.
options[].imageUrlstring or null
options[].highlightsarray of string
options[].warrantystring or null
options[].recommendedboolean
options[].linesarray of object
options[].lines[].idstring
options[].lines[].descriptionstring
options[].lines[].quantitynumber
options[].lines[].unitPriceCentsinteger
options[].lines[].optionalboolean
options[].lines[].defaultSelectedboolean
options[].lines[].kindstring or null
options[].lines[].memberPriceAppliedbooleanPriced at the item's member price: the member discount skips it.
options[].pricingobject
options[].pricing.totalCentsinteger
options[].pricing.depositCentsinteger
options[].pricing.memberobject or nullWith the membership add-on: the total as a member, the saving and the plan's price.
options[].pricing.monthlyCentsinteger or null"As low as" per month over months (an illustration, subject to approval); null when it cannot be financed.
options[].pricing.monthsinteger
featuresarray of object
features[].featurestring
features[].includedarray of boolean
membershipobject
membership.alreadyMemberboolean
membership.currentPlanNamestring or null
membership.planobject or null
membership.plan.idstring
membership.plan.namestring
membership.plan.descriptionstring or null
membership.plan.priceCentsinteger
membership.plan.billingFrequencystring
membership.plan.termMonthsinteger
membership.plan.serviceDiscountPercentnumber
membership.plan.materialDiscountPercentnumber
financingobject
financing.availableboolean
financing.methodsarray of string
financing.monthsinteger
financing.disclosurestring
approvalobject
approval.termsstring
approval.depositRequiredboolean

Start presenting a quote

POST /organizations/{organizationId}/quotes/{quoteId}/presentations

Records that the signed-in person started presenting the quote (for the close-rate and time-per-step analytics). Returns the presentation to report steps to.

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 toolpresentations_start (toolset sales)

Parameters

NameInTypeRequiredDescription
quoteIdpathstringYes

Request body

FieldTypeRequiredDescription
jobIdstring or nullNo

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/quotes/{quoteId}/presentations" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jobId":"job_id"}'

Response

201: the answer's fields
FieldTypeDescription
idstring
quoteIdstring
jobIdstring or null
templateIdstring or null
presenterUserIdstring
technicianIdstring or null
outcomeenumOne of OPEN, WON, LOST.
stepSecondsobject
currentStepenum or nullOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
optionsViewedarray of string
chosenOptionIdstring or null
chosenPositioninteger or null
optionCountinteger
membershipAddedboolean
membershipIdstring or null
financingViewedboolean
lostReasonstring or null
startedAtstring (date-time)
lastActivityAtstring (date-time)
completedAtstring (date-time) or null

Report presentation progress

PATCH /organizations/{organizationId}/quotes/{quoteId}/presentations/{presentationId}

Adds seconds spent per step since the last report (capped per step), the current step, options viewed and whether financing was shown; lost ends it without approval (with a reason). Ignored once it ended.

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 toolpresentations_track (toolset sales)

Parameters

NameInTypeRequiredDescription
quoteIdpathstringYes
presentationIdpathstringYes

Request body

FieldTypeRequiredDescription
addSecondsobjectNoSeconds spent on each step, e.g. { INTRO: 40, OPTIONS: 180 }.
currentStepenum or nullNoOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
viewedOptionIdsarray of stringNoUp to 10 items.
financingViewedbooleanNo
lostobject or nullNo
lost.reasonstring or nullNoUp to 500 characters.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/quotes/{quoteId}/presentations/{presentationId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"addSeconds":{},"currentStep":"INTRO","viewedOptionIds":["viewedOption_id"]}'

Response

200: the answer's fields
FieldTypeDescription
idstring
quoteIdstring
jobIdstring or null
templateIdstring or null
presenterUserIdstring
technicianIdstring or null
outcomeenumOne of OPEN, WON, LOST.
stepSecondsobject
currentStepenum or nullOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
optionsViewedarray of string
chosenOptionIdstring or null
chosenPositioninteger or null
optionCountinteger
membershipAddedboolean
membershipIdstring or null
financingViewedboolean
lostReasonstring or null
startedAtstring (date-time)
lastActivityAtstring (date-time)
completedAtstring (date-time) or null

The customer approves in the presentation

POST /organizations/{organizationId}/quotes/{quoteId}/presentations/{presentationId}/complete

Acts for the customer: with membership, signs them up for the template's membership plan (its agreement signed with the same signature) and applies member pricing; then approves the chosen option with the signature through the existing quote approval (terms, snapshot, device) and records the presentation as won. Take the deposit afterwards with POST /quotes/{quoteId}/deposits (cash, check) or the customer's card on /q/{token}.

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

Permissionquotes.approve
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolpresentations_complete (toolset sales)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Parameters

NameInTypeRequiredDescription
quoteIdpathstringYes
presentationIdpathstringYes

Request body

FieldTypeRequiredDescription
optionIdstringYes
selectedLineIdsarray of stringNoUp to 200 items.
signatureNamestringYesUp to 200 characters.
signatureDataUrlstring or nullNoThe signature drawn on the tablet: a data:image/png;base64 URL.
termsstring or nullNoThe quote terms shown. Up to 5000 characters.
membershipobject or nullNo
membership.planIdstringYesThe template's membership plan.
membership.termsstringYesThe membership agreement shown.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/quotes/{quoteId}/presentations/{presentationId}/complete" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"optionId":"option_id","signatureName":"string"}'

Response

200: the answer's fields
FieldTypeDescription
presentationobject
presentation.idstring
presentation.quoteIdstring
presentation.jobIdstring or null
presentation.templateIdstring or null
presentation.presenterUserIdstring
presentation.technicianIdstring or null
presentation.outcomeenumOne of OPEN, WON, LOST.
presentation.stepSecondsobject
presentation.currentStepenum or nullOne of INTRO, FINDINGS, OPTIONS, FINANCING, APPROVAL.
presentation.optionsViewedarray of string
presentation.chosenOptionIdstring or null
presentation.chosenPositioninteger or null
presentation.optionCountinteger
presentation.membershipAddedboolean
presentation.membershipIdstring or null
presentation.financingViewedboolean
presentation.lostReasonstring or null
presentation.startedAtstring (date-time)
presentation.lastActivityAtstring (date-time)
presentation.completedAtstring (date-time) or null
quoteobject
quote.idstring
quote.identifierstring
quote.statusstring
quote.approvedTotalCentsinteger or null
quote.approvedDepositCentsinteger or null
quote.publicTokenstring or null
membershipIdstring or null

On this page