Wire an agent to a number
Connect an external or hosted agent, set its voice stack, and answer real calls.
An Skysay agent is the phone-side configuration that decides how a call is heard, thought about, and spoken. There are three modes:
external_audio— your own audio agent, connected over a webhook + audio stream URL. Useconnect_external_agentfor the common case.external_text— your own text agent; Skysay handles STT/TTS around it.hosted— Skysay runs the conversation for you. The default engine is Standard speech-to-text, a model, then text-to-speech. You can instead choose GPT-Live 1, which listens and speaks at once.
Or do it in the workspace
Everything below has a workspace equivalent. The Agents page lists what you have built, one row per AI agent, and each row says where it has got to:
| Status | What it means |
|---|---|
| Stopped | You switched it off, so it answers nothing until you resume it |
| Needs a voice | Something is unchosen or refused, so nothing would answer yet |
| Ready to test | It can hold a conversation in the browser; nothing is dialled |
| Tested | It has taken at least one call |
| Needs attention | A number is attached and its registration is waiting on you -- the carrier asked for more information, or turned the registration down |
| Number activating | A number is attached and the carrier has not finished |
| Live | A number is attached and activated, and nothing about the agent blocks a call |
The Voice setup column shows the speech recognition, language model, and speech synthesis selections for hosted cascade AI agents. Native live engines show their saved model and voice. External integrations are identified as externally managed instead of being assigned platform model defaults.
Select an AI agent's name or voice setup to open its details panel, including the voice and any separate backend model. Open editor takes you to its configuration. You can search by name, language, phone number, or model and filter by voice setup. These filters apply to the loaded list; the page reports when only part of the workspace is loaded.
The summary describes saved settings, which can differ from the published configuration used by calls. Draft identifies saved unpublished settings; it is separate from whether the AI agent is ready to test. Activity combines calls today and the last call time, with the counting timezone shown below the list.
The Next column names the one thing to do next and links to the control that does it, so a row is never a dead end. Needs a voice covers more than a missing voice -- a suspended agent or an unreachable external endpoint lands there too -- so a row whose problem is something else sends you to the agent's Overview, where every problem is listed beside the control that clears it. Needs attention is the one state where the wait is yours rather than the carrier's: its next step is Fix the number, which opens that number on the Numbers page, where the checklist names what was asked for. Number activating prescribes no step, because nothing in the workspace makes the carrier finish sooner.
New AI agent opens three steps: Start (a blank agent, a preset, or bring your own), Identity (name, opening language, first message and instructions) and Voice. Choosing GPT-Live 1 at the Voice step replaces the three Standard components with one engine.
Inside an agent, the section rail groups the work: Agent (Overview, Identity, Voice, Languages), Uses (Knowledge, Tools, Phone), Conversation (Flow, Validation), Ship (Test, Versions, Call history) and Advanced (Tuning, Credentials). Overview is the landing section: it lists what is left to do before the agent can be published, and what still blocks publishing, each beside the control that fixes it.
A new agent also gets a short checklist on Overview, Three steps to the first call. It is an onboarding aid: it disappears once the walk to a first call is over — the agent has held a conversation, has a number attached, or has been stopped — leaving At a glance as the top of the section. Its rows do not repeat the editor's controls — each one takes you to the control that owns the step.
Talk to it, at the top of the agent editor, opens the test panel beside the editor, where you choose Browser or Phone and whether you are testing the Current draft or the Published snapshot. On a wide screen the panel is already open beside the editor and carries its own start control, so the header button appears when the panel is collapsed or the window is too narrow to show it.
Editing does not publish: Publish changes shows exactly which fields changed and asks before it writes. It is offered only while the draft differs from the published snapshot — when the editor says the page matches what is published, there is nothing to publish.
Stopping and resuming an agent
Stop answering, at the top of the agent editor, takes one AI agent off the air without deleting anything. Resume puts it back.
A stopped agent answers nothing:
- no inbound or outbound telephone calls,
- no browser test, and
- no homepage demo.
Nothing else changes. The agent, its voice stack, its knowledge, its tools and its attached numbers all stay exactly as they were, and you can keep editing and publishing the draft while it is stopped.
Resume lifts the stop and does nothing else. It restores no snapshot: the agent comes back on whatever is published at that point and on the numbers routed to it then, and it answers as soon as the rest of its setup allows. So this is the safe way to take an agent out of service for an hour, a weekend, or a season — and if you publish changes while it is stopped, those are the changes it comes back with.
The one visible consequence is on your numbers: a number routed to a stopped agent stops answering, and the Phone numbers page shows it as a problem naming the stopped agent as the reason, until you resume the agent or route that number somewhere else.
Over the API the same control is the status field:
you › stop my receptionist answering
→ update_agent(agent_id=..., status="inactive") # agents:writestatus accepts active and inactive, and rejects anything else with a
400 — as it does any change to an agent whose stored status is neither of
those. A call to a stopped agent is refused with the agent_inactive reason.
A call already in progress when you stop the agent is not cut off.
A suspended agent is not a stopped one
If an Skysay operator has suspended an agent, that is a different state and
you cannot clear it yourself — status will not move the agent out of it.
Contact support.
1. Create the agent
you › connect my audio agent at wss://my-agent.example/stream
→ connect_external_agent(...) # agents:writecreate_agent is the full form (mode, first message, system prompt, voice
stack). connect_external_agent is the shortcut for an external_audio agent
with webhook and audio-stream URLs.
Changing an agent later
An edit through update_agent (PATCH /v1/agents/{agent_id}) takes effect on
the agent's next call. An edit to its prompt, greeting, language or voice
stack publishes the agent in the same step. If the agent could not be
published that way (a greeting its voice cannot speak, for example), the edit
is refused and nothing changes. Tools, the recording setting and tuning are
read when each call starts, so they always took effect on the next call.
Calls already under way keep what they started with, and an edit that
changes none of these, such as a new name, publishes nothing. An edit made
while the agent is not hosted is published when it becomes hosted again.
This fixes a bug. On an agent that had already been published, an edit to its prompt, greeting, language or voice stack used to be stored while calls kept running the last published version until the next publish from the editor.
A hosted agent that has never been published is published by the first save
that leaves it valid. A save that does not is still kept, and the agent's
metadata.publication says why:
{"state": "unpublished", "reason": "publication_variables_invalid", "where": "system_prompt.en", "issue": "UNDECLARED_VARIABLE"}reason is one of publication_stack_incomplete,
publication_greeting_missing, publication_variables_invalid,
publication_workflow_invalid, publication_language_unavailable or
publication_refused; where names the part of the agent to fix, and
issue carries the call-variables code when there is one. Once published,
the record reads {"state": "published"} with the other fields empty. It
belongs to the platform: a metadata replace keeps it as it was.
Three settings belong to set_agent_voice_stack
(PATCH /v1/agents/{agent_id}/voice-stack):
- Follow the caller (
metadata.follow_caller):update_agentrefuses a change to it and keeps it through a metadata replace. - Phone menu navigation (
metadata.navigation): on by default for every AI agent.update_agentrefuses a change to it and keeps it through a metadata replace, so an explicit off survives. See Phone menu navigation. - A new language for an agent that runs a workflow:
set_agent_voice_stacktranslates the workflow into that language first, including every language Follow the caller for all languages adds.update_agentrefuses a language the workflow does not speak yet, and so does a switch back tohostedthat would publish one.
Read Skysay phone-number coverage during a conversation
Attach this built-in tool to a hosted AI agent when it should answer questions about Skysay's supported phone-number countries:
{"type": "builtin", "name": "get_phone_number_coverage"}The tool uses the same maintained, customer-safe coverage data as
GET /v1/coverage-matrix. It works on inbound and outbound calls, browser tests,
homepage demos, and SMS read-tool requests. It reads information without
ordering a number or asking for confirmation. Each AI agent must explicitly
have the tool attached; it is not enabled automatically.
Use it with hosted AI agents without a conversation flow. A published conversation flow cannot run this built-in as a tool step.
The model can call it with {} for a compact country list, or
{"countries":["Estonia","Germany"]} for capabilities and onboarding details.
Use up to ten English country names. Existing coverage aliases such as EE,
US and UK also work. Unrecognized names appear in not_listed; they do not
cause a fallback to all countries. Results include returned_count,
total_countries and has_more, with at most 200 country rows returned.
Coverage is not a live inventory check. inventory_checked is false:
availability of an exact number, current pricing, and country and number-type
activation requirements still need a current number-catalog check. Instruct
the AI agent to answer from the tool result and avoid promising an immediately
available number or instant activation.
When attaching it through PATCH /v1/agents/{agent_id}, preserve the complete
existing tools list and send its previously read value as expected_tools.
Replacing the list with only this entry removes the other tools.
2. Choose a voice stack
For hosted or external-text agents, pick a conversation engine
first. Standard uses STT / LLM / TTS providers from the catalog. GPT-Live 1
uses a GPT-Live voice and a backend model instead. get_agent_catalog lists
selectable providers plus conversation_engines; filter Standard rows by
component and language (for example, language=et requests the current
Estonian options).
→ get_agent_catalog(component="tts", language="et", metered_only=true) # agents:read or coverage:read
→ set_agent_voice_stack(agent_id="ag_...", ...) # agents:writeSet metered_only=true only when you want component-metered choices; omit it
to see every runnable adapter.
set_agent_voice_stack validates the effective selection against the declared
runtime and its credential and billing contracts. The catalog exposes the
runtime-declared combinations; a provider voice's advertised language count
alone does not establish that its complete call stack is runnable.
The tool maps to PATCH /v1/agents/{agent_id}/voice-stack; its language fields
match the generated API reference.
Keep a fixed language per call, or enable Auto multilingual and choose all supported languages or your own subset. The underlying Follow the caller setting is optional: publish it only with a listening configuration that supports the accepted languages together. The AI agent may then switch among the call's admitted profiles on a clear request or stable language evidence, without changing its shared tools or business instructions. A voice's multilingual label alone is not proof of simultaneous listening support. See Multilingual calls for the API setting, boundaries, and test flow.
From MCP, use list_agents for a bounded newest-first page, get_agent for a
single current projection, update_agent for ordinary mutable fields, and
get_agent_voice_stack to read a published stack back. The key's organization
is authoritative: omit the redundant organization_id, or repeat only the
same workspace. A different workspace, project, or agent is rejected before a
configuration write or preview render; treat that MCP error as a tenant
validation failure, not a retry prompt for another workspace identifier.
preview_voice is the MCP Listen action. It has agents:write because it can
contact a provider or validate a BYOK credential and is rate-limited per
workspace; it is not a read-only preview. Browser-session create and settle
remain browser/REST operations because they require a browser-owned LiveKit
audio participant and later client settlement.
Optional outgoing ambience
An agent may also publish one optional audio_environment selection with its
voice stack. It is strict and version-pinned:
{ preset_id, asset_version, volume }. Select it from
GET /v1/audio-environments
or MCP list_audio_environments; Off is an explicit selection with volume
zero. An enabled preset needs a positive whole-number volume. Unknown fields,
unknown presets, a missing asset version, and a mismatched version are refused
rather than guessed or replaced.
This is an outgoing background track, shared across the agent's language
profiles. It is never caller/STT input and does not change the chosen voice,
language, or call's frozen voice-stack configuration. If you audition it with
preview_voice, supply non-blank text; the exact text and selected language
are preserved rather than substituted or translated. A preview is a bounded
local audition, not proof of a receiver-side final mix.
Choose a voice, not a vendor. The Voice step shows voices available for your AI agent's language: play a sample, and picking a voice sets the provider, the model, and the exact voice id together. Voices in the sidebar is the same gallery unfiltered, for browsing across every provider and language before or without editing an AI agent.
Browsing and listening are open in every language a provider advertises, which is wider than the set an AI agent can take calls in — a call also needs transcription and a qualified stack. A voice you can hear in a language but not yet deploy in says so on its card rather than disappearing from it.
Each card shows only what the provider supplied — structured gender, its own tags, its own description — plus the source of each of those fields. Nothing is inferred from the audio: no guessed age, accent, personality, or quality score. Cost and latency each carry the source of that number, which may be a measurement from real calls, a figure the vendor publishes, or a catalog estimate that says it is one.
Galleries are bounded, ordered selections rather than an unrestricted provider dump, and they say when they are showing a slice. Filtering and search on the Voices page are answered by the server, so a voice on a later page is still found. An engine that cannot be billed yet, or that this catalog does not offer for calls in the language you are filtering by, stays visible and disabled with that reason rather than disappearing, and if an existing AI agent uses a voice outside the current selection, its exact stored choice stays in that agent's Voice step instead of being silently replaced.
The full Voices page has four horizontal, searchable multi-select filters: Language, Accent, Character, and Provider. Several values in one filter are an "any of" selection; filters together narrow the result. Character is only the provider's own style or persona metadata, never a gender proxy. The page derives its values from the cached provider inventory, so a new provider voice or declared language does not need a frontend list or manual promotion.
Use Hear it as your AI agent to listen before saving. It speaks any sentence you type — your AI agent's first message by default — in any language the provider advertises. The audio is never stored, and the request is bounded and rate-limited per workspace.
The gallery is backed by the provider's scoped cached inventory rather than a frontend-maintained voice list. New provider voices therefore appear after a cache refresh without a frontend release or human promotion step. A failed refresh serves the last good inventory, and a bounded partial inventory never proves that an unobserved voice was removed.
On the full library page, a cached audio sample is a fast path for a selected target language only when its catalog provenance proves that match. At present, an Skysay ingestion-synthesized sample proves English; a provider sample with no spoken-language assertion is not assumed to be English. With no Language filter or chosen preview language, an existing recording can play as published and the row labels unverified spoken language rather than inferring one. A row with no suitable sample still offers Play, which makes the bounded, metered, rate-limited live preview request. If it cannot run, the page shows a local safe error rather than a provider credential, trace, or raw provider response. Several matching selected languages require an explicit choice in the row's searchable preview-language control; the library never silently chooses the first one. Entering your own text deliberately uses that live request and speaks the exact wording you enter without translation. With no typed text, the library uses a localized sample sentence for the chosen language when it has one; otherwise it asks you for text instead of substituting English.
Cartesia Sonic 3.6 follows that same contract. Its managed gallery contains only the provider's public, non-owned voices. If you use your own Cartesia credential, its owned or cloned voice IDs remain private to that credential's workspace and project; test the exact ID with your own text before saving it. The preview does not substitute a managed credential or a fallback voice.
On Skysay credentials, a new selection must belong to the managed scoped inventory. With your own provider credential, validation and preview stay scoped to that exact credential; cloned and private voice IDs can work without becoming visible to another workspace. A preview started with your credential never falls back to an Skysay one.
Skysay does not automatically choose a default or recommended language or voice. Select both explicitly. If a provider later withdraws an existing stored voice, the editor keeps that exact choice visible with a warning; it is never silently replaced by a fallback voice. An exact provider response that the voice no longer exists blocks future call admission until you choose a new voice or a successful explicit validation clears the marker.
Several languages, one hosted agent
Choose the agent's supported languages, an opening language, and one shared voice. You do not need separate copies of its identity, instructions, tools, knowledge, and business policy. Optional language overrides can change a voice, transcriber, or exact greeting without duplicating the rest of the agent. Unspecified values inherit the shared settings; clearing an override restores inheritance. An exact greeting is optional, not a publish checklist for every language.
Saving the voice stack publishes the effective profiles. A browser test or outbound call selects a published language before admission, and the resolved configuration is frozen for that call. A later agent edit does not change an in-progress call or its quoted component identities. This is fixed-language calling, not automatic mid-call language switching.
See Multilingual outbound calls for the request fields and application boundary. A Voice Library language filter controls an audition; it does not grant the agent permission to call in that language.
Interruptions and barge-in
Every hosted phone call, in every language, requires 500 ms of continuous
caller speech before it interrupts the agent unless the agent sets its own
threshold. That is the default, not a floor: an explicit min_speech_ms is
honoured on phone calls in every language down to 150 ms, and a value below
150 ms is raised to 150 ms. Browser and web calls do not apply this setting: it
is still stored on the agent and returned to you, but those calls are not phone
calls and keep the browser stack's own threshold. The default deliberately
reduces false interruptions from very brief background audio and backchannels
while keeping a sustained request such as “stop” interruptible. Sustained
background speech can still be treated as caller speech.
After the caller stops speaking, the agent waits for a fixed endpointing
hold before it treats the turn as finished. On a phone call, an agent whose
language has a trained turn detector holds for 600 ms when the detector
judges the caller finished and up to 1200 ms when it judges them probably
not finished; every other language holds for 800 ms. These holds keep a
caller's mid-sentence pause (after their name, before a number, while leaving a
message) from ending the turn on a narrowband phone line. A browser test call
runs the shorter browser timings. The interruption_sensitivity presets move that hold by a
different amount in each class, because in a language without the turn detector
the hold is the whole end-of-turn decision:
| Preset | Interruption threshold | Hold, language with the turn detector | Hold, every other language |
|---|---|---|---|
balanced (default) | 500 ms | 600 ms, up to 1200 ms | 800 ms |
low | 750 ms | 900 ms, up to 1800 ms | 1100 ms |
high | 150 ms | 260 ms, up to 600 ms | 600 ms |
Languages with the trained turn detector are Arabic, German, English, Spanish, French, Hindi, Indonesian, Italian, Japanese, Korean, Dutch, Portuguese, Turkish and Chinese. Every other language, including Sinhala, Tamil and Estonian, uses the right-hand hold column. See Turn detection by language for how the two signals behind this table work and for guidance on choosing a preset per language.
The hold is a minimum wait, not the reply time. A turn never ends before voice detection reports the end of speech, which takes about 250 ms of silence, and never before the final transcript of what the caller said has arrived, which depends on the speech-to-text provider. The agent editor shows these figures for the agent's own language under Interruption sensitivity, with a timeline of when that agent's recorded replies actually started.
What turn_taking in set_agent_voice_stack adds is per-agent control over
that threshold, the endpointing hold, and whether an interruption must also
carry recognized words. interruption_sensitivity, min_speech_ms and
silence_hold_ms all apply in every language. The preset sets both the
threshold and the hold from the table above; an explicit min_speech_ms or
silence_hold_ms takes precedence over the preset for its own knob, so you can
combine a preset with one explicit number. min_interruption_words has its own
condition and is the one setting here with a non-zero default; it is described
under the table.
The controls are applied when a call starts; saving a voice stack never changes an in-progress call.
| Setting | Effect on a hosted phone call |
|---|---|
interruption_sensitivity | Every language. balanced is the default: the 500 ms threshold and the platform hold. low requires 750 ms of continuous speech and holds longer after it. high uses 150 ms for callers who need a more responsive threshold, and holds for less. The hold each preset sets depends on whether the language has the trained turn detector (table above), and it is a minimum wait, not the reply time. min_speech_ms and silence_hold_ms, when set, take precedence for their knob. |
min_speech_ms | Every language. An explicit 80–2000 ms interruption threshold, overriding any sensitivity preset. On a phone call it is honoured down to 150 ms; a value below 150 ms is raised to 150 ms. A phone call without it, and without a preset, uses the 500 ms default. Browser and web calls store it but do not apply it. |
silence_hold_ms | Every language. The shortest wait, 100–2000 ms, after the caller stops speaking before their turn can end. It overrides the platform hold and any sensitivity preset. A value below about 250 ms has no effect, because voice detection needs that much silence to report the end of speech, and the wait is longer whenever the final transcript arrives later than this value. |
min_interruption_words | 0–5. Defaults to 1 on hosted English calls and to 0 (off) everywhere else. An interruption must ALSO carry at least this many recognized words from the caller, on top of the speech-duration threshold. Set 0 explicitly to turn it off. Effective only on stacks whose transcriber reports words fast enough — see below. |
barge_in_speech_rms | Deprecated. Accepted, stored and returned for compatibility only; the runtime does not apply it to call behavior. Use interruption_sensitivity, min_speech_ms and min_interruption_words to control interruptions. |
A wordless burst that clears the threshold does not end the reply. If no caller speech follows, the runtime classifies the interruption as false: the agent’s reply pauses for up to a second and then resumes from where it paused.
Requiring words as well as duration
min_interruption_words addresses a different problem from the duration
threshold. Raising min_speech_ms rejects short bursts, but a long stretch of
non-speech audio — a television, a passing vehicle, a cough — can clear any
duration threshold you would still be willing to interrupt on. Requiring a
recognized word rejects that class outright: with min_interruption_words: 1,
the agent yields the floor only when the caller has both held it for the
duration threshold and actually said something.
Both conditions must hold. The setting never lowers the duration threshold and never makes an interruption happen sooner.
The default
A hosted English agent that has not set min_interruption_words runs with
1: one recognized word as well as the duration threshold. Agents in every
other language default to 0 and run on the duration threshold alone, because
the requirement is only enforceable where the transcriber can report a word in
time (see below).
To turn the requirement off on an English agent, set min_interruption_words
to 0 explicitly. An explicit 0 is stored and returned; leaving the setting
out is what selects the default.
It is accepted and returned for any agent in any language, but it is
effective only where the transcriber emits words fast enough to land inside
the interruption decision — today that is the Deepgram stacks, which serve
English and Estonian. On every other stack the setting is stored, returned
unchanged by get_agent_voice_stack, and ignored at call time: those calls run
on the duration threshold alone, exactly as they do with the setting unset. The
distinction is the transcriber's timing, not the language: a transcriber that
reports a caller's first word a second or two after they start speaking would
refuse ordinary interruptions rather than only the wordless ones, which is
worse than not having the setting.
Sounds that do not count as words
On hosted English calls, short listening noises from the caller do not count
toward min_interruption_words. "mm-hm", "uh-huh", "yes", "yeah", "okay",
"right", "sure", and hesitation sounds such as "uh" and "um" are what a caller
says to show they are following, not to take the floor, so a transcript
containing nothing but one or two of them will not interrupt the agent however
long the caller holds it.
This is English-only, and deliberately so. Estonian is the other language whose
transcriber is fast enough for min_interruption_words to take effect, and an
Estonian agent that sets it runs the word requirement in full — but every word
counts there, including "jah" and "okei", because the equivalent list has not
been measured for that language. Applying an English list to it would refuse
nothing while this page claimed otherwise.
The caller is still heard. What they said is delivered to the agent when the reply ends, so a caller who says "okay" is answered afterwards rather than ignored — they simply do not cut the agent off mid-sentence to do it.
Anything else counts, including short words that sound similar in isolation. "no" is a word; so is "wait", "stop", and "huh". So is any phrase that mixes the two: "yes but" carries a word the agent will stop for.
Expect a small added delay when the setting is on. On the Deepgram stacks transcription results arrive about once a second, so roughly half the time the caller's first word is already recognized when the duration threshold opens and the interruption is unchanged; the rest of the time it is delayed until the next result, by up to about half a second. A word recognized before the threshold opens costs nothing — the interruption still happens the moment the caller has spoken for long enough.
1 is the English default for this reason. Values above 1 require most of a
phrase before the agent will stop, which callers experience as an agent that
does not listen.
Four protections are not settings and are not English-only. On every hosted phone call, in any language:
- The runtime holds what the caller is transcribed as saying while the agent is preparing or delivering a reply, and delivers it once that reply ends. Background speech picked up by transcription therefore cannot cut the agent off mid-sentence.
- For agents using the Standard conversation engine on an inbound call, or on a call bound to an agent workflow, the opening line is not interrupted by the phone being picked up. While the opening line plays, caller speech shorter than one second of continuous speech — a "hello?", a syllable, a breath — does not cut it, in any language and whatever the agent's interruption threshold. What the caller said is still transcribed and is answered once the opening line has finished, so nobody who spoke is ignored. A caller who keeps speaking for longer than a second has taken the floor: the ordinary interruption rules apply from that moment and the opening line stops as any reply would. Speech that arrives after the call is answered but before the opening line has started — the callee answering into a line that has not said anything yet — is held exactly like a pickup during the opening and is answered once the opening line has finished; on a workflow-bound call a held "hello" typically costs one clarification turn rather than being lost, since the identity question has not been heard yet. The opening line itself is still spoken immediately in every case — nothing waits for that early speech before starting it. The opening line also cannot be cancelled before its first audio frame reaches the caller, so mis-transcribed background noise cannot open a call in silence. On an outbound call with the Standard engine none of this applies: the agent lets the person say hello first, and its opening is an ordinary reply the person can interrupt. See Who speaks first. If the opening line cannot be synthesised at all, a short line in the call's own language is played in its place; that substitute exists for English, Estonian, Sinhala and Tamil, and a call in another language, or one whose substitute also fails to synthesise, still opens in silence. GPT-Live 1 and Gemini Live agents handle barge-in on the model side: the opening line is not held uninterruptible by this protection, and a pickup-shaped "hello?" may still cut it. Workflow-bound calls cannot use either engine, so the early-speech hold described above applies to Standard agents only.
- When an interruption does qualify, the agent plays on for a bounded moment instead of stopping at the exact instant it is cut, so the sound it is part way through finishes rather than being clipped. This is a time budget of up to 300 ms, and it decides when the agent stops rather than where in a word: an interruption early in a long word still lands inside it, one syllable later. What it buys is a less abrupt stop and a shorter gap when a brief interruption turns out to be false.
- When the agent does stop, the last fraction of a second it had already committed to the call is played out under a quick fade rather than dropped, so the final word ends instead of being clipped part way through. On agents whose voice provider reports word timings — today ElevenLabs and Cartesia, which covers English and Estonian — the stop is moved to the end of the word being spoken whenever that end is close enough to reach; otherwise, and on every other voice, the fade is used. Either way the agent is silent within about half a second of the interruption qualifying, and it never plays anything the caller was not already about to hear.
None of these needs configuration, and browser tests are unaffected.
When the caller seems to start talking before a reply
If the caller appears to start speaking just as a reply is ready, the agent waits rather than talk over them. Background noise — a television, traffic, people nearby — can sound like the start of speech, so on a hosted phone call the agent does not wait on sound alone forever:
- On hosted English calls transcribed by Deepgram, with
min_interruption_wordsat 1 or more (the English default), the agent waits at most 1.5 seconds when no words are recognized, then speaks. Listening sounds such as "mm-hm", "okay" or "uh" do not count as words. That is longer than it takes the transcriber to report a caller's first word. If the caller does say a word during the wait, the agent keeps waiting for them, up to eight seconds. - A reply that starts after such a wait still stops for the caller: the
caller's recognized words (
min_interruption_wordsof them, one by default), held for the interruption threshold, interrupt it as usual. Continued noise with no words does not. - Every other language and transcriber keeps the eight-second limit until the transcriber's word timing for that stack has been measured. The speech-to-speech engines are unchanged.
This is not a setting. interruption_sensitivity, min_speech_ms and
silence_hold_ms do not change it.
3. Point a number at it
Number rules decide what happens when someone calls a number and which agents
can use it to place calls. Update them with update_number_rules
(numbers:write); read them with get_number_rules (numbers:read).
To take a number back off an agent, POST /v1/phone-numbers/{number_id}/detach-agent (numbers:write). It is a pure
control-plane unbind: the number stays imported and owned by the workspace,
its rules become disabled, and no carrier work happens. Inbound calls are
declined until you attach an agent again or change the rules. Detaching a
number that already answers without an agent replays as a no-op with
idempotent: true. The same action is available in the workspace on the
agent's Phone section and on the number's page.
If you decided to detach from a view of the number that may since have moved
on — a page a teammate reassigned under you — name the binding you expect.
Send expected_agent_id, or expected_agent_endpoint_id when the rule answers
through an endpoint you cannot resolve to an agent. A number that by then
answers with a different binding is refused with 409 and nothing changes,
so you cannot take a colleague's fresh assignment offline by confirming a stale
screen. Naming an identity the rule no longer carries is refused the same way:
an expectation that cannot be confirmed is not treated as confirmed. A binding
that is gone entirely is not a conflict — the state you wanted already holds,
so it replays as the idempotent: true no-op. Send neither field to detach
whichever agent answers.
Test in the browser first
Before assigning a live number, use a browser test with welcome credit or purchased funds to hear your agent. No number provisioning is needed. A separate, normally funded phone test is needed to prove the carrier route.
Check incoming-call configuration
Open Phone numbers and select the number. The existing Activation checks distinguish purchase and carrier-order completion from incoming-call configuration. A purchased, active number can still need attention before its AI agent can answer.
A warning in the number list points to the explanation in the selected number's checks. Follow the suggested action, such as assigning an AI agent or contacting support when pricing is unavailable. Supported call-in/call-out capabilities describe the number's features; they do not prove that a call can connect right now.
These checks describe saved configuration. Available funds, current capacity, call policy and carrier reachability are still checked when a call arrives. Outbound support depends on the selected destination and is checked when the call is requested. Refresh the page after correcting a prerequisite.
Bring your own agent
Two of the three modes let your own application do the thinking. Both are
created in the workspace from Agents → Bring your own
agent, or over the API with
POST /v1/agents.
Webhook agent (external_text)
Skysay runs speech-to-text and text-to-speech around your app, so the app only deals in text.
- What Skysay sends. A
POSTto your webhook URL for each call lifecycle event and each transcript turn, signed withX-Agent-Telco-TimestampandX-Agent-Telco-Signature. - What your app returns. The words to say next, as a text or NDJSON response. Skysay speaks them to the caller.
- Where the URL goes. The Webhook URL field on the create form, or
webhook_urlonPOST /v1/agentswith"mode": "external_text".
Realtime audio agent (external_audio)
Your app hears and speaks the call itself; Skysay runs no speech stack for it.
- What Skysay sends. Call lifecycle events to your webhook URL, and
bidirectional call audio to your realtime audio URL — the gateway opens that
wss://connection while the route is active. - What your app returns. Audio, on the same connection.
- Where the URLs go. The Webhook URL and Realtime audio URL fields
on the create form, or
webhook_urlplusaudio_stream_urlonPOST /v1/agentswith"mode": "external_audio".connect_external_agentis the shortcut for the same pair.
POST /v1/agents answers with the agent's signing secret in
agent_endpoint.webhook_secret, once. Save it immediately: every later read
returns [REDACTED]. It signs each event and tool call Skysay sends to your
webhook; verify X-Agent-Telco-Timestamp and X-Agent-Telco-Signature as
described in Post-call results.
Agents created before 24 September 2026 cannot retrieve their signing secret;
recreate the agent or contact support.
Webhook signature verification, idempotency and backpressure handling stay in
your app. GET /v1/agents/{agent_id}/handoff returns the generated setup
contract for either mode: the endpoints it will call, the events to expect,
and the headers to verify.
To send a phone number's calls to a realtime audio agent, open Phone numbers, select the number, and pick Send live audio to my app under "When someone calls".