REST endpoints for phone in ServFlo: 11 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.
GET /organizations/{organizationId}/phone/settings
The phone system's settings: on/off, the mode (twilio, or fake = simulated calls), business hours in the business's timezone, after-hours voicemail or forwarding, ring timeout and the default ring group, voicemail greeting, call recording with its consent announcement and retention, transcription and AI summaries, missed-call follow-ups and text-back, and the webhook URLs Twilio calls. Read-only.
fake = simulated calls (development, tests). One of fake, twilio, off.
enabled
boolean
twilioSource
enum
Managed: the business's ServFlo Twilio sub-account (billed at Twilio's cost + 20%); OWN: its own Twilio account connected in Settings → Messaging. One of MANAGED, OWN.
managedAccount
object or null
The ServFlo sub-account (MANAGED, once made).
managedAccount.accountSidHint
string
managedAccount.status
enum
One of ACTIVE, SUSPENDED, CLOSED.
managedAccount.fake
boolean
managedAccount.suspendReason
string or null
managedAccount.closeAfter
string (date-time) or null
accountConnected
boolean
The Twilio account calls run on is ready: the ServFlo sub-account (active), or the business's own account connected for texts.
browserCalling
boolean
The browser phone's API key and TwiML App exist.
businessHours
object
afterHoursAction
enum
One of VOICEMAIL, FORWARD.
afterHoursForwardNumber
string or null
ringTimeoutSeconds
integer
defaultRingGroupId
string or null
voicemailGreeting
string or null
recordCalls
boolean
announceRecording
boolean
recordingAnnouncement
string or null
businessState
string or null
recordingRetentionDays
integer
transcribeCalls
boolean
aiSummaries
boolean
missedCallFollowUp
boolean
missedCallTextBack
boolean
missedCallTextBody
string or null
webhookUrls
object or null
Where Twilio sends calls (set on bought or assigned numbers automatically).
Change how calls are handled from the next call on: business hours, after hours, ring timeout, default ring group, voicemail greeting, recording (announced by default; two-party-consent states are always announced), retention, transcription, AI summaries (metered against AI credits), missed-call follow-ups and the missed-call text (sent only to known customers whose number is OK to text). enabled: false stops answering calls.
Permission
phone.manage (Owner, Admin)
Risk
write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
fake = simulated calls (development, tests). One of fake, twilio, off.
enabled
boolean
twilioSource
enum
Managed: the business's ServFlo Twilio sub-account (billed at Twilio's cost + 20%); OWN: its own Twilio account connected in Settings → Messaging. One of MANAGED, OWN.
managedAccount
object or null
The ServFlo sub-account (MANAGED, once made).
managedAccount.accountSidHint
string
managedAccount.status
enum
One of ACTIVE, SUSPENDED, CLOSED.
managedAccount.fake
boolean
managedAccount.suspendReason
string or null
managedAccount.closeAfter
string (date-time) or null
accountConnected
boolean
The Twilio account calls run on is ready: the ServFlo sub-account (active), or the business's own account connected for texts.
browserCalling
boolean
The browser phone's API key and TwiML App exist.
businessHours
object
afterHoursAction
enum
One of VOICEMAIL, FORWARD.
afterHoursForwardNumber
string or null
ringTimeoutSeconds
integer
defaultRingGroupId
string or null
voicemailGreeting
string or null
recordCalls
boolean
announceRecording
boolean
recordingAnnouncement
string or null
businessState
string or null
recordingRetentionDays
integer
transcribeCalls
boolean
aiSummaries
boolean
missedCallFollowUp
boolean
missedCallTextBack
boolean
missedCallTextBody
string or null
webhookUrls
object or null
Where Twilio sends calls (set on bought or assigned numbers automatically).
POST /organizations/{organizationId}/phone/connect
Turn the phone system on. Makes the business's ServFlo Twilio sub-account the first time (MANAGED, the default; usage billed at Twilio's cost + 20%), then creates an API key and a TwiML App in that account (or in the business's own Twilio account when it chose OWN) for the browser phone; safe to repeat (the App's URLs are refreshed). In fake mode it records simulated ids. Call GET /phone/settings first to see the mode.
Permission
phone.manage (Owner, Admin)
Risk
sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP tool
phone_connect (toolset marketing)
Plan
Needs the Phone system add-on.
Approval
Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.
fake = simulated calls (development, tests). One of fake, twilio, off.
enabled
boolean
twilioSource
enum
Managed: the business's ServFlo Twilio sub-account (billed at Twilio's cost + 20%); OWN: its own Twilio account connected in Settings → Messaging. One of MANAGED, OWN.
managedAccount
object or null
The ServFlo sub-account (MANAGED, once made).
managedAccount.accountSidHint
string
managedAccount.status
enum
One of ACTIVE, SUSPENDED, CLOSED.
managedAccount.fake
boolean
managedAccount.suspendReason
string or null
managedAccount.closeAfter
string (date-time) or null
accountConnected
boolean
The Twilio account calls run on is ready: the ServFlo sub-account (active), or the business's own account connected for texts.
browserCalling
boolean
The browser phone's API key and TwiML App exist.
businessHours
object
afterHoursAction
enum
One of VOICEMAIL, FORWARD.
afterHoursForwardNumber
string or null
ringTimeoutSeconds
integer
defaultRingGroupId
string or null
voicemailGreeting
string or null
recordCalls
boolean
announceRecording
boolean
recordingAnnouncement
string or null
businessState
string or null
recordingRetentionDays
integer
transcribeCalls
boolean
aiSummaries
boolean
missedCallFollowUp
boolean
missedCallTextBack
boolean
missedCallTextBody
string or null
webhookUrls
object or null
Where Twilio sends calls (set on bought or assigned numbers automatically).
POST /organizations/{organizationId}/phone/softphone-token
What the browser phone needs for the signed-in person: mode TWILIO with a one-hour Twilio Voice access token (identity derived from the user; receives the ring group's calls, places calls through the business number), FAKE (simulated calls), OFF (phone system off) or UNAVAILABLE (connect voice first). Nothing else changes.
Calls ringing for the signed-in person's ring groups and calls they are on: what the browser phone and the screen pop show. Poll every few seconds. Read-only (simulated calls nobody answered are ended as Twilio would).
One of RINGING, IN_PROGRESS, COMPLETED, MISSED, VOICEMAIL, FAILED.
items[].fake
boolean
A simulated call (SERVFLO_VOICE=fake).
items[].fromNumber
string
items[].toNumber
string
items[].otherNumber
string
The customer's side of the call.
items[].phoneNumber
object or null
items[].phoneNumber.id
string
items[].phoneNumber.label
string
items[].phoneNumber.e164
string
items[].source
enum or null
The tracked source of the number called (PERSONAL: someone's own line); null = untracked. One of MAIN, WEBSITE, GOOGLE_BUSINESS, CAMPAIGN, QR_CODE, BUSINESS_UNIT, PRINT, OTHER, PERSONAL.
items[].campaign
object or null
items[].campaign.id
string
items[].campaign.name
string
items[].businessUnit
object or null
items[].businessUnit.id
string
items[].businessUnit.name
string
items[].customer
object or null
items[].customer.id
string
items[].customer.name
string
items[].matchedCustomerCount
integer
items[].user
object or null
Who answered (inbound) or placed it (outbound).
items[].user.id
string
items[].user.name
string
items[].bridgeNumber
string or null
items[].ivrDigit
string or null
items[].afterHours
boolean
items[].startedAt
string (date-time)
items[].answeredAt
string (date-time) or null
items[].endedAt
string (date-time) or null
items[].durationSeconds
integer or null
Talk time.
items[].billedMinutes
integer or null
items[].voicemail
boolean
items[].recording
object
items[].recording.status
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
items[].recording.announced
boolean
items[].recording.durationSeconds
integer or null
items[].recording.available
boolean
items[].recording.deletedAt
string (date-time) or null
items[].recording.error
string or null
items[].transcriptStatus
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
items[].transcript
string or null
Only for callers holding phone.recordings, on GET /phone/calls/{callId}.
items[].summaryStatus
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
items[].summary
string or null
The AI call summary (Claude, from the transcript).
items[].summaryError
string or null
items[].followUp
object
items[].followUp.status
enum
One of NONE, OPEN, DONE.
items[].followUp.assignee
object or null
items[].followUp.doneAt
string (date-time) or null
items[].textBack
object or null
items[].textBack.status
string
items[].textBack.messageId
string or null
items[].job
object or null
items[].job.id
string
items[].job.identifier
string
items[].request
object or null
items[].request.id
string
items[].request.identifier
string
items[].notes
string or null
items[].ai
object or null
Set when the call was routed to the AI receptionist.
items[].ai.startedAt
string (date-time) or null
items[].ai.endedAt
string (date-time) or null
items[].ai.outcome
string or null
What the AI receptionist did: BOOKED, RESCHEDULED, REQUEST, MESSAGE, TRANSFERRED, ENDED, ABANDONED, FAILED, TIMEOUT, DRAINED; null while live.
items[].ai.callerTurns
integer
items[].ai.voiceSeconds
integer or null
AI voice seconds (metered as ai_voice.minutes).
items[].ai.message
string or null
A message it took for the office.
items[].ai.turns
array of object or null
The conversation; only for callers holding phone.recordings, on GET /phone/calls/{callId}.
POST /organizations/{organizationId}/phone/simulate
Only with simulated voice (SERVFLO_VOICE=fake; 409 otherwise): an inbound call from from to one of the business's numbers, through the same steps as Twilio's webhooks (routing, caller match, menu, recording, transcript, AI summary, follow-up, text-back). RING leaves it ringing for the browser phone; ANSWERED, MISSED and VOICEMAIL play it through. now is test-only (refused in production).
Permission
phone.manage (Owner, Admin)
Risk
write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
One of RINGING, IN_PROGRESS, COMPLETED, MISSED, VOICEMAIL, FAILED.
fake
boolean
A simulated call (SERVFLO_VOICE=fake).
fromNumber
string
toNumber
string
otherNumber
string
The customer's side of the call.
phoneNumber
object or null
phoneNumber.id
string
phoneNumber.label
string
phoneNumber.e164
string
source
enum or null
The tracked source of the number called (PERSONAL: someone's own line); null = untracked. One of MAIN, WEBSITE, GOOGLE_BUSINESS, CAMPAIGN, QR_CODE, BUSINESS_UNIT, PRINT, OTHER, PERSONAL.
campaign
object or null
campaign.id
string
campaign.name
string
businessUnit
object or null
businessUnit.id
string
businessUnit.name
string
customer
object or null
customer.id
string
customer.name
string
matchedCustomerCount
integer
user
object or null
Who answered (inbound) or placed it (outbound).
user.id
string
user.name
string
bridgeNumber
string or null
ivrDigit
string or null
afterHours
boolean
startedAt
string (date-time)
answeredAt
string (date-time) or null
endedAt
string (date-time) or null
durationSeconds
integer or null
Talk time.
billedMinutes
integer or null
voicemail
boolean
recording
object
recording.status
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
recording.announced
boolean
recording.durationSeconds
integer or null
recording.available
boolean
recording.deletedAt
string (date-time) or null
recording.error
string or null
transcriptStatus
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
transcript
string or null
Only for callers holding phone.recordings, on GET /phone/calls/{callId}.
summaryStatus
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
summary
string or null
The AI call summary (Claude, from the transcript).
summaryError
string or null
followUp
object
followUp.status
enum
One of NONE, OPEN, DONE.
followUp.assignee
object or null
followUp.assignee.id
string
followUp.assignee.name
string
followUp.doneAt
string (date-time) or null
textBack
object or null
textBack.status
string
textBack.messageId
string or null
job
object or null
job.id
string
job.identifier
string
request
object or null
request.id
string
request.identifier
string
notes
string or null
ai
object or null
Set when the call was routed to the AI receptionist.
ai.startedAt
string (date-time) or null
ai.endedAt
string (date-time) or null
ai.outcome
string or null
What the AI receptionist did: BOOKED, RESCHEDULED, REQUEST, MESSAGE, TRANSFERRED, ENDED, ABANDONED, FAILED, TIMEOUT, DRAINED; null while live.
ai.callerTurns
integer
ai.voiceSeconds
integer or null
AI voice seconds (metered as ai_voice.minutes).
ai.message
string or null
A message it took for the office.
ai.turns
array of object or null
The conversation; only for callers holding phone.recordings, on GET /phone/calls/{callId}.
GET /organizations/{organizationId}/phone/ai-receptionist
The AI receptionist's settings: on/off, when it answers (ALWAYS, AFTER_HOURS, OVERFLOW instead of voicemail), greeting and instructions (whether the greeting introduces it as the virtual assistant, and how it names a known caller: callerGreeting), the trade template, voice and language, who a transfer rings, and what it may do (book real arrival windows and move a known caller's visit, take requests and cancellation requests, say pricebook prices by priceMode, tell a known caller their balance, text links). Also the trade templates, the greeting as spoken, and whether this server can run it (keys, booking mode, problems to fix). Read-only.
Takes service requests, and a known caller's cancellation requests (never cancels).
priceMode
enum
Off: never a price. STARTING_AT: pricebook prices as 'starting at', the technician confirms. EXACT: the pricebook price. One of OFF, STARTING_AT, EXACT.
quotePriceRanges
boolean
Deprecated: true when priceMode is not OFF.
canTextLinks
boolean
canShareBalance
boolean
Tells a known caller their open balance after their name matches.
announceAssistant
boolean
The greeting says "I'm the virtual assistant"; the transcription notice is always said.
callerGreeting
enum
How the greeting names a caller whose number matches a customer: FIRST_NAME ("Hi Sarah"), TITLE_LAST_NAME ("Hello Mrs. Johnson"; the customer's own title, else the first name) or GENERIC (no name). Unknown numbers always get the generic greeting; the caller is still verified before their visits or account. One of FIRST_NAME, TITLE_LAST_NAME, GENERIC.
templates
array of object
templates[].key
string
templates[].name
string
templates[].greeting
string
suggestedTemplate
string or null
The website's trade, when a template matches it.
greetingPreview
string
The greeting as spoken, with the AI disclosure.
readiness
object
readiness.mode
enum
fake = scripted speech and a scripted model (tests). One of fake, live, off.
readiness.ready
boolean
It can answer calls on this server with these settings.
readiness.keys
object
readiness.keys.deepgram
boolean
readiness.keys.elevenlabs
boolean
readiness.keys.openai
boolean
readiness.keys.anthropic
boolean
readiness.bookingMode
enum
Booking real windows needs online booking in SLOTS mode; otherwise it takes requests. One of SLOTS, REQUEST.
Change the AI receptionist from the next call on. When on, Claude answers calls by voice in the chosen mode, always says the call is transcribed, says it is the virtual assistant in the greeting unless announceAssistant is false, names a caller whose number matches a customer by callerGreeting (FIRST_NAME, TITLE_LAST_NAME with the customer's own title, or GENERIC; unknown numbers are always greeted generically, and a known number is still verified by full name and service ZIP before their visits or account), and never claims to be a person (asked, it says it is the business's AI assistant). It may book arrival windows and move a known caller's visit to one (canBook; the online booking rules, confirmed with the caller first), take requests, messages and a known caller's cancellation request (canTakeRequests; it never cancels: the office confirms, with a follow-up on the call and a notification), say pricebook prices (priceMode OFF, STARTING_AT or EXACT; never a cost), tell a known caller their open balance once their name matches (canShareBalance), text known customers a link (canTextLinks; consent applies), and transfer to a ring group or number. It never invents prices or availability. Its model use is metered against AI credits and its voice minutes as ai_voice.minutes. transferRingGroupId must be one of the business's ring groups. Needs the phone add-on, except to switch it off.
Permission
phone.manage (Owner, Admin)
Risk
write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
Always: it answers every call. AFTER_HOURS: it answers outside business hours (instead of the after-hours voicemail or forward). OVERFLOW: it answers when a call would go to voicemail (no one answered, no one to ring, after-hours voicemail). One of ALWAYS, AFTER_HOURS, OVERFLOW.
greeting
string or null
No
Spoken first; blank = the trade template's greeting. Up to 400 characters.
instructions
string or null
No
What the business wants it to know (policies, areas, what to mention). Never put prices here unless you want them said. Up to 4000 characters.
template
string
No
A trade template key (GET /phone/ai-receptionist lists them). Up to 40 characters.
voiceProvider
enum
No
One of DEEPGRAM, ELEVENLABS, OPENAI.
voiceId
string or null
No
The provider's voice id; blank = its default for the language. Up to 100 characters.
language
enum
No
en (English) or es (Spanish). One of en, es.
transferRingGroupId
string or null
No
Who a transfer rings (GET /phone/ring-groups); else transferNumber, else the default group.
transferNumber
string or null
No
A +E.164 number a transfer dials when no ring group is set. Up to 32 characters.
canBook
boolean
No
Book real arrival windows (needs online booking in SLOTS mode).
canTakeRequests
boolean
No
Take a service request (lead) for the office, and a known caller's request to cancel a visit (it never cancels: the office confirms).
priceMode
enum
No
Pricebook prices when a caller asks: OFF (never a price; a technician confirms it), STARTING_AT ("starting at $X", the technician confirms the final price; the default), EXACT (the pricebook price). Never a cost or margin, never a price the pricebook does not hold. One of OFF, STARTING_AT, EXACT.
quotePriceRanges
boolean
No
Deprecated: use priceMode. true = STARTING_AT, false = OFF; ignored when priceMode is given.
canTextLinks
boolean
No
Text a known caller a booking, payment or portal link (consent rules apply).
canShareBalance
boolean
No
Tell a known caller (caller ID matches a customer) their open balance, only after they say their name and it matches; then it offers to text the payment link (needs canTextLinks).
announceAssistant
boolean
No
Say "I'm the virtual assistant" in the greeting (default on). Off: the greeting keeps only the transcription notice. Either way it never claims to be a person and says it is the business's virtual (AI) assistant when asked.
callerGreeting
enum
No
How the greeting names a caller whose number matches a customer: FIRST_NAME ("Hi Sarah", the default), TITLE_LAST_NAME ("Hello Mrs. Johnson": the customer's own title (Mr., Mrs., Ms., Miss, Dr., Mx.) and last name; without both it says the first name, without a usable name nothing) or GENERIC (no name). Unknown numbers always get the generic greeting. Caller ID can be faked, so it still verifies the caller (full name and service ZIP) before talking about their visits or account. One of FIRST_NAME, TITLE_LAST_NAME, GENERIC.
Takes service requests, and a known caller's cancellation requests (never cancels).
priceMode
enum
Off: never a price. STARTING_AT: pricebook prices as 'starting at', the technician confirms. EXACT: the pricebook price. One of OFF, STARTING_AT, EXACT.
quotePriceRanges
boolean
Deprecated: true when priceMode is not OFF.
canTextLinks
boolean
canShareBalance
boolean
Tells a known caller their open balance after their name matches.
announceAssistant
boolean
The greeting says "I'm the virtual assistant"; the transcription notice is always said.
callerGreeting
enum
How the greeting names a caller whose number matches a customer: FIRST_NAME ("Hi Sarah"), TITLE_LAST_NAME ("Hello Mrs. Johnson"; the customer's own title, else the first name) or GENERIC (no name). Unknown numbers always get the generic greeting; the caller is still verified before their visits or account. One of FIRST_NAME, TITLE_LAST_NAME, GENERIC.
templates
array of object
templates[].key
string
templates[].name
string
templates[].greeting
string
suggestedTemplate
string or null
The website's trade, when a template matches it.
greetingPreview
string
The greeting as spoken, with the AI disclosure.
readiness
object
readiness.mode
enum
fake = scripted speech and a scripted model (tests). One of fake, live, off.
readiness.ready
boolean
It can answer calls on this server with these settings.
readiness.keys
object
readiness.keys.deepgram
boolean
readiness.keys.elevenlabs
boolean
readiness.keys.openai
boolean
readiness.keys.anthropic
boolean
readiness.bookingMode
enum
Booking real windows needs online booking in SLOTS mode; otherwise it takes requests. One of SLOTS, REQUEST.
GET /organizations/{organizationId}/phone/ai-receptionist/voice-sample
Speaks the receptionist's opening line ("Thanks for calling <business>…") in a voice, so the owner can compare voices before choosing one. Returns a short 8 kHz WAV, base64, exactly as a caller hears it on the phone. Changes nothing (the voice is chosen with PATCH …/phone/ai-receptionist). The voices offered per provider and language are AI_VOICE_CATALOG (voiceId blank = the provider's default). MONEY: a live sample uses AI credits (about 1 per sample, for the provider's text-to-speech); 402 PLAN_LIMIT_REACHED when the business has none left. Limited per business. 409 when this server has no voice for that provider; simulated = silence (SERVFLO_VOICE_AI=fake), free.
POST /organizations/{organizationId}/phone/ai-receptionist/simulate
Only with simulated voice and SERVFLO_VOICE_AI=fake (409 otherwise): a call from from goes through routing to the receptionist, which runs the Twilio Media Streams protocol in-process with scripted speech-to-text (script: the caller's lines) and a scripted model (/tool name {json} calls a tool, bye ends the call, anything else is echoed). Writes the call log, the conversation, the request or booking it made and the summary, as a real call would. now is test-only.
Permission
phone.manage (Owner, Admin)
Risk
write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
One of RINGING, IN_PROGRESS, COMPLETED, MISSED, VOICEMAIL, FAILED.
call.fake
boolean
A simulated call (SERVFLO_VOICE=fake).
call.fromNumber
string
call.toNumber
string
call.otherNumber
string
The customer's side of the call.
call.phoneNumber
object or null
call.phoneNumber.id
string
call.phoneNumber.label
string
call.phoneNumber.e164
string
call.source
enum or null
The tracked source of the number called (PERSONAL: someone's own line); null = untracked. One of MAIN, WEBSITE, GOOGLE_BUSINESS, CAMPAIGN, QR_CODE, BUSINESS_UNIT, PRINT, OTHER, PERSONAL.
call.campaign
object or null
call.campaign.id
string
call.campaign.name
string
call.businessUnit
object or null
call.businessUnit.id
string
call.businessUnit.name
string
call.customer
object or null
call.customer.id
string
call.customer.name
string
call.matchedCustomerCount
integer
call.user
object or null
Who answered (inbound) or placed it (outbound).
call.user.id
string
call.user.name
string
call.bridgeNumber
string or null
call.ivrDigit
string or null
call.afterHours
boolean
call.startedAt
string (date-time)
call.answeredAt
string (date-time) or null
call.endedAt
string (date-time) or null
call.durationSeconds
integer or null
Talk time.
call.billedMinutes
integer or null
call.voicemail
boolean
call.recording
object
call.recording.status
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
call.recording.announced
boolean
call.recording.durationSeconds
integer or null
call.recording.available
boolean
call.recording.deletedAt
string (date-time) or null
call.recording.error
string or null
call.transcriptStatus
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
call.transcript
string or null
Only for callers holding phone.recordings, on GET /phone/calls/{callId}.
call.summaryStatus
enum
One of NONE, PENDING, DONE, FAILED, SKIPPED.
call.summary
string or null
The AI call summary (Claude, from the transcript).
call.summaryError
string or null
call.followUp
object
call.followUp.status
enum
One of NONE, OPEN, DONE.
call.followUp.assignee
object or null
call.followUp.doneAt
string (date-time) or null
call.textBack
object or null
call.textBack.status
string
call.textBack.messageId
string or null
call.job
object or null
call.job.id
string
call.job.identifier
string
call.request
object or null
call.request.id
string
call.request.identifier
string
call.notes
string or null
call.ai
object or null
Set when the call was routed to the AI receptionist.
call.ai.startedAt
string (date-time) or null
call.ai.endedAt
string (date-time) or null
call.ai.outcome
string or null
What the AI receptionist did: BOOKED, RESCHEDULED, REQUEST, MESSAGE, TRANSFERRED, ENDED, ABANDONED, FAILED, TIMEOUT, DRAINED; null while live.
call.ai.callerTurns
integer
call.ai.voiceSeconds
integer or null
AI voice seconds (metered as ai_voice.minutes).
call.ai.message
string or null
A message it took for the office.
call.ai.turns
array of object or null
The conversation; only for callers holding phone.recordings, on GET /phone/calls/{callId}.
Run this business's pending phone work now instead of waiting for the worker: recording downloads into storage, AI summaries, simulated calls nobody answered, and recordings past retention. now is test-only (refused in production).
Permission
phone.manage (Owner, Admin)
Risk
write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.