DevelopersAPI referenceEngagement

Web chat API

REST endpoints for web chat in ServFlo: 7 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
Website chat settingsGET /organizations/{organizationId}/web-chat/settingsread
Change the website chat settingsPATCH /organizations/{organizationId}/web-chat/settingswrite
Get a website chatGET /organizations/{organizationId}/web-chats/{webChatId}read
Answer a website chatPOST /organizations/{organizationId}/web-chats/{webChatId}/replysensitive
Take over a website chat, or let the AI answerPOST /organizations/{organizationId}/web-chats/{webChatId}/aiwrite
Mark a website chat readPOST /organizations/{organizationId}/web-chats/{webChatId}/readwrite
Link a website chat to a customerPOST /organizations/{organizationId}/web-chats/{webChatId}/customerwrite

Website chat settings

GET /organizations/{organizationId}/web-chat/settings

The website chat widget's settings (Settings → Messaging → Website chat): on or off, who answers first (chosen, and what applies with the plan), the PEOPLE_FIRST wait, the greeting, colour and "Text me replies" wording (each with its default), and the snippet to paste on another website. Read-only.

Permissionengagement.read (Owner, Admin, Dispatcher)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolwebChat_settings (toolset marketing)

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/web-chat/settings" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
enabledboolean
answerModeenum or nullWhat was chosen; null = the default. One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
effectiveAnswerModeenumWhat applies now: AI modes act as PEOPLE_ONLY on a plan without the AI agent. One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
aiIncludedbooleanThe plan includes the AI agent (Grow and Pro).
aiWaitSecondsinteger
greetingstring or null
defaultGreetingstring
colorstring or null
defaultColorstringThe website theme's primary colour, used when color is null.
consentTextstring or null
defaultConsentTextstring
organizationSlugstring
widgetUrlstring
snippetstringHTML to paste on another website (embed.js).
updatedAtstring or null

Change the website chat settings

PATCH /organizations/{organizationId}/web-chat/settings

Customer-facing: turns the chat on the business's websites on or off and sets who answers first (AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY; null = the default), the PEOPLE_FIRST wait in seconds (30–1800), the greeting, the colour (#rrggbb; null = the website theme's) and the "Text me replies" checkbox label (null = the default wording). Only the fields sent change. An AI mode needs the AI agent (Grow and Pro); turning the chat off or choosing PEOPLE_ONLY works on any plan.

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

Request body

FieldTypeRequiredDescription
enabledbooleanNoShow the chat on the business's websites.
answerModeenum or nullNoWho answers first: AI_FIRST, PEOPLE_FIRST (the AI after aiWaitSeconds or outside business hours) or PEOPLE_ONLY. null = the default (AI_FIRST with the AI agent on the plan, else PEOPLE_ONLY). AI_FIRST and PEOPLE_FIRST need the AI agent (Grow and Pro). One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
aiWaitSecondsintegerNoPEOPLE_FIRST: seconds the team has to answer before the AI replies (120). 30–1800.
greetingstring or nullNoThe widget's first line; null or empty = the default greeting. Up to 300 characters.
colorstring or nullNo#rrggbb for the widget; null = the website theme's primary colour.
consentTextstring or nullNoThe "Text me replies" checkbox label (unticked by default); null or empty = the default wording. Up to 600 characters.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/web-chat/settings" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"answerMode":"AI_FIRST","aiWaitSeconds":30}'

Response

200: the answer's fields
FieldTypeDescription
enabledboolean
answerModeenum or nullWhat was chosen; null = the default. One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
effectiveAnswerModeenumWhat applies now: AI modes act as PEOPLE_ONLY on a plan without the AI agent. One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
aiIncludedbooleanThe plan includes the AI agent (Grow and Pro).
aiWaitSecondsinteger
greetingstring or null
defaultGreetingstring
colorstring or null
defaultColorstringThe website theme's primary colour, used when color is null.
consentTextstring or null
defaultConsentTextstring
organizationSlugstring
widgetUrlstring
snippetstringHTML to paste on another website (embed.js).
updatedAtstring or null

Get a website chat

GET /organizations/{organizationId}/web-chats/{webChatId}

One website chat for the team: the transcript oldest first (the visitor's, the AI's and the team's messages, and ServFlo's notes; a staff answer that also went out by text or email with its status), what the visitor gave (name, phone, email: unverified), whether they ticked "Text me replies", whether they are still in the chat, whether the AI is answering (and why it stopped), and where an answer would go now. Does not mark it read (POST …/read). Read-only.

Permission: inbox.read (Owner, Admin, Dispatcher, Technician (own jobs)); risk read (OAuth scope servflo.read).

Permissioninbox.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolwebChat_get (toolset marketing)

Parameters

NameInTypeRequiredDescription
webChatIdpathstringYesA website chat, from GET /conversations?kinds=CHAT (its key is chat:<id>) or a notification.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/web-chats/{webChatId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
idstring
keystringIts Inbox conversation: customer:<id>, phone:<+E.164>, email:<address> or chat:<id>.
customerIdstring or nullLinked by the team; never from what the visitor typed.
customerNamestring or null
visitorNamestring or nullWhat the visitor typed: unverified.
phonestring or null
emailstring or null
textMebooleanThe visitor ticked "Text me replies" for that number (30 days).
visitorOnlinebooleanThe visitor's widget is open now.
visitorSeenAtstring or null
aiActivebooleanThe AI answers this chat (false after a hand-off or a take-over).
handoffReasonstring or null
answerModeenumWho answers first in this business now (with the plan). One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
aiIncludedboolean
aiRepliesinteger
pageUrlstring or null
createdAtstring
lastVisitorMessageAtstring or null
lastReadAtstring or null
unreadboolean
replyobject
reply.viaenumWhere an answer goes now: the chat while the visitor is in it, else text (if they asked) or email. One of CHAT, SMS, EMAIL.
reply.tostring or null
messagesarray of objectOldest first.
messages[].idstring
messages[].authorenumVisitor: the website visitor. AI: the AI agent. STAFF: someone on the team. SYSTEM: ServFlo's note. One of VISITOR, AI, STAFF, SYSTEM.
messages[].bodystring
messages[].staffUserIdstring or null
messages[].staffNamestring or nullThe first name the visitor saw.
messages[].deliveredViaenum or nullA staff answer that also went out by text or email (the visitor had left). One of CHAT, SMS, EMAIL.
messages[].messageIdstring or nullThat text's or email's message (GET /messages/{messageId}).
messages[].deliveryStatusstring or nullThat text's or email's status.
messages[].deliveryReasonstring or null
messages[].createdAtstring

Answer a website chat

POST /organizations/{organizationId}/web-chats/{webChatId}/reply

Customer-facing: the caller's answer (1–2,000 characters, shown with their first name only) goes into the visitor's chat, and the AI stops answering this chat. When the visitor already left it also goes out from the business: by text when they gave a phone and ticked "Text me replies" (the business's texting number; STOP and quiet-hours rules apply), else by email when they gave one; their answers come back into the same Inbox conversation. delivery says which; problem says why a text or email was refused (the answer stays in the chat). Supports Idempotency-Key.

Permission: inbox.reply (Owner, Admin, Dispatcher, Technician (own jobs)); risk sensitive (OAuth scope servflo.sensitive).

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

Parameters

NameInTypeRequiredDescription
webChatIdpathstringYesA website chat, from GET /conversations?kinds=CHAT (its key is chat:<id>) or a notification.

Request body

FieldTypeRequiredDescription
bodystringYesThe answer, as the visitor will read it. Up to 2000 characters.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/web-chats/{webChatId}/reply" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body":"string"}'

Response

200: the answer's fields
FieldTypeDescription
messageIdstring
deliveryenumOne of CHAT, SMS, EMAIL.
outboundMessageIdstring or nullThe text's or email's message, when one went out.
problemstring or null

Take over a website chat, or let the AI answer

POST /organizations/{organizationId}/web-chats/{webChatId}/ai

active: false ("Take over"): the AI stops answering this chat and the visitor reads that someone from the team joined (first name only). active: true ("Let AI answer"): the AI answers again, at once if the visitor's newest message is unanswered; needs an AI answer mode and the AI agent on the plan (Grow and Pro). Answers with the chat.

Permission: inbox.reply (Owner, Admin, Dispatcher, Technician (own jobs)); risk write (OAuth scope servflo.write).

Permissioninbox.reply
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolwebChat_setAi (toolset marketing)

Parameters

NameInTypeRequiredDescription
webChatIdpathstringYesA website chat, from GET /conversations?kinds=CHAT (its key is chat:<id>) or a notification.

Request body

FieldTypeRequiredDescription
activebooleanYes

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/web-chats/{webChatId}/ai" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"active":true}'

Response

200: the answer's fields
FieldTypeDescription
idstring
keystringIts Inbox conversation: customer:<id>, phone:<+E.164>, email:<address> or chat:<id>.
customerIdstring or nullLinked by the team; never from what the visitor typed.
customerNamestring or null
visitorNamestring or nullWhat the visitor typed: unverified.
phonestring or null
emailstring or null
textMebooleanThe visitor ticked "Text me replies" for that number (30 days).
visitorOnlinebooleanThe visitor's widget is open now.
visitorSeenAtstring or null
aiActivebooleanThe AI answers this chat (false after a hand-off or a take-over).
handoffReasonstring or null
answerModeenumWho answers first in this business now (with the plan). One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
aiIncludedboolean
aiRepliesinteger
pageUrlstring or null
createdAtstring
lastVisitorMessageAtstring or null
lastReadAtstring or null
unreadboolean
replyobject
reply.viaenumWhere an answer goes now: the chat while the visitor is in it, else text (if they asked) or email. One of CHAT, SMS, EMAIL.
reply.tostring or null
messagesarray of objectOldest first.
messages[].idstring
messages[].authorenumVisitor: the website visitor. AI: the AI agent. STAFF: someone on the team. SYSTEM: ServFlo's note. One of VISITOR, AI, STAFF, SYSTEM.
messages[].bodystring
messages[].staffUserIdstring or null
messages[].staffNamestring or nullThe first name the visitor saw.
messages[].deliveredViaenum or nullA staff answer that also went out by text or email (the visitor had left). One of CHAT, SMS, EMAIL.
messages[].messageIdstring or nullThat text's or email's message (GET /messages/{messageId}).
messages[].deliveryStatusstring or nullThat text's or email's status.
messages[].deliveryReasonstring or null
messages[].createdAtstring

Mark a website chat read

POST /organizations/{organizationId}/web-chats/{webChatId}/read

Opening a chat: it is read for the whole team (until the visitor writes again) and the caller's own website chat notifications for it are read. Changes nothing the visitor sees.

Permission: inbox.read (Owner, Admin, Dispatcher, Technician (own jobs)); risk write (OAuth scope servflo.write).

Permissioninbox.read
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolwebChat_markRead (toolset marketing)

Parameters

NameInTypeRequiredDescription
webChatIdpathstringYesA website chat, from GET /conversations?kinds=CHAT (its key is chat:<id>) or a notification.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/web-chats/{webChatId}/read" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
keystring
lastReadAtstring
notificationsReadinteger

Link a website chat to a customer

POST /organizations/{organizationId}/web-chats/{webChatId}/customer

The team decides who the visitor is: the chat joins the customer's Inbox conversation (customerId null unlinks it). What the visitor typed is never proof; nothing changes for the visitor and nothing is copied to the customer. Create the customer first (customers.create) for someone new.

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

Parameters

NameInTypeRequiredDescription
webChatIdpathstringYesA website chat, from GET /conversations?kinds=CHAT (its key is chat:<id>) or a notification.

Request body

FieldTypeRequiredDescription
customerIdstring or nullYesThe customer, or null to unlink.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/web-chats/{webChatId}/customer" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerId":"customer_id"}'

Response

200: the answer's fields
FieldTypeDescription
idstring
keystringIts Inbox conversation: customer:<id>, phone:<+E.164>, email:<address> or chat:<id>.
customerIdstring or nullLinked by the team; never from what the visitor typed.
customerNamestring or null
visitorNamestring or nullWhat the visitor typed: unverified.
phonestring or null
emailstring or null
textMebooleanThe visitor ticked "Text me replies" for that number (30 days).
visitorOnlinebooleanThe visitor's widget is open now.
visitorSeenAtstring or null
aiActivebooleanThe AI answers this chat (false after a hand-off or a take-over).
handoffReasonstring or null
answerModeenumWho answers first in this business now (with the plan). One of AI_FIRST, PEOPLE_FIRST, PEOPLE_ONLY.
aiIncludedboolean
aiRepliesinteger
pageUrlstring or null
createdAtstring
lastVisitorMessageAtstring or null
lastReadAtstring or null
unreadboolean
replyobject
reply.viaenumWhere an answer goes now: the chat while the visitor is in it, else text (if they asked) or email. One of CHAT, SMS, EMAIL.
reply.tostring or null
messagesarray of objectOldest first.
messages[].idstring
messages[].authorenumVisitor: the website visitor. AI: the AI agent. STAFF: someone on the team. SYSTEM: ServFlo's note. One of VISITOR, AI, STAFF, SYSTEM.
messages[].bodystring
messages[].staffUserIdstring or null
messages[].staffNamestring or nullThe first name the visitor saw.
messages[].deliveredViaenum or nullA staff answer that also went out by text or email (the visitor had left). One of CHAT, SMS, EMAIL.
messages[].messageIdstring or nullThat text's or email's message (GET /messages/{messageId}).
messages[].deliveryStatusstring or nullThat text's or email's status.
messages[].deliveryReasonstring or null
messages[].createdAtstring

On this page