How a call ends
How the AI agent ends a call with end_call on each conversation engine, the standing instruction every agent with end_call receives, and the check-in and polite ending when both sides go quiet.
A call ends in one of three ways:
- the other party hangs up;
- the AI agent ends it with the
end_calltool; - Skysay ends it under one of its safety rules.
This page covers the second, and the one safety rule that watches for a conversation that has gone quiet. The complete set of reasons a call can end with is in Post-call results.
One ending comes from a provider rather than a person or a rule: when the
call's transcriber refuses the request it is opened with (most often because it
does not take the call's language), Skysay ends the call with ended_reason
model_session_lost and reason_detail transcriber_refused_request instead
of leaving the line open with nobody listening. See When the transcriber refuses the request.
If the caller leaves while Skysay is still preparing the call, Skysay checks that the original caller is still connected before starting providers and reporting media startup. A departure detected at those checks stops setup; it is not recorded as a completed conversation. Inbound phone calls also require confirmation that SIP actually answered before Skysay reports an answered call and starts the conversation model.
The agent ends the call with end_call
New agents have end_call. A hosted AI agent you create with
New AI Agent in Agents, or through POST /v1/agents without a tools
field, gets the built-in end_call tool, so it can hang up when the
conversation is over. A tools list you send is taken as written: to create
an agent that never ends a call itself, send a list without end_call (an
empty list is allowed). On an existing agent, switch End call on or off
under Tools in the agent editor. Without the tool an agent can say goodbye,
but the line stays open until the other side hangs up or a safety rule ends
the call.
When the conversation is over, the agent calls the built-in end_call tool.
Skysay then plays its goodbye and hangs up if the caller does not resume
speaking before the close is committed. When that agent-requested ending
completes, the call reports ended_reason agent_completed. A safety rule
that takes over first reports its own ending reason instead.
Where the goodbye comes from depends on the conversation engine:
- Standard (speech-to-text, model, text-to-speech): the agent passes its
goodbye as the tool's
message, and Skysay speaks it in the agent's voice. The agent does not say a separate goodbye first. - GPT-Live 1 and Gemini Live: these engines speak for themselves, so there
is no separate voice for Skysay to speak a text line with. The agent says its
own short goodbye and then calls
end_callin the same turn. Skysay lets that goodbye finish playing, then hangs up. The tool'smessageis not spoken on these engines, and it is not recorded as something the caller heard. On these enginesend_callonly ends the call after the agent's goodbye; see On live engines,end_callneeds the agent's goodbye.
Either way, the wait for the goodbye is bounded. If it does not finish within about 15 seconds, the call is ended anyway.
On live engines, the spoken goodbye ends the call
A live voice model (GPT-Live 1, Gemini Live, or Eleven Realtime when enabled)
says its goodbye in its own voice, and GPT-Live 1 often does not follow it
with end_call. So on these engines Skysay does not wait for the tool: when an agent that has end_call enabled says its goodbye, Skysay hangs
up for it.
- After a goodbye, Skysay waits until the line has been quiet for about
2 seconds, then ends the call with
ended_reasonagent_completed. A "bye" said back only restarts that wait. If the other side says something that needs an answer, the agent answers and the call stays open. - If the agent says goodbye again after the other side has spoken, the call ends then, whatever the other side is playing. This is what stops an agent repeating "goodbye" to a voicemail box or a recording that never pauses.
- Any other line from the agent starts the count again.
Skysay judges what the line does, not particular words, so this works in any
language, and a word that can greet or take leave, such as "ciao", is judged
by its place in the call: a greeting at the start is not a goodbye. It applies to incoming, outgoing and
browser test calls. It is paused while the agent is working through a phone
menu or waiting on hold, and it is off for an agent without end_call.
You do not need to instruct the agent to call end_call after its goodbye on
these engines. On GPT-Live 1, instructions that forbid speaking, or repeat
"call end_call", do not make the ending more reliable. Tell the agent when the
conversation is over; the goodbye does the rest.
This is a judgement about one spoken line, so it can be wrong. An agent that says goodbye while it still expects an answer is disconnected if the other side takes more than about 2 seconds to start replying, so do not have an agent end a line with a goodbye unless the conversation is over.
On live engines, end_call needs the agent's goodbye
A live voice model decides for itself when to call end_call, and it can call
it at the wrong moment: in testing, a Gemini Live agent answered a caller's
first sentence with "How can I help you today?" and called end_call in the
same breath. So on GPT-Live 1, Gemini Live and Eleven Realtime, Skysay checks
the call before it hangs up.
- The agent's latest line was its goodbye: the hang-up goes ahead as
described above. A goodbye said one turn earlier counts too, so an agent
that says "goodbye", hears "bye" and then calls
end_callwithout another word still ends the call. - It was anything else, or the agent has not said anything yet: the call stays open. (A first line still being spoken is waited for and judged.) The agent is told the call has not ended and carries on. It does not say anything about this to the caller.
- The caller had just spoken and the agent answered with
end_calland no words: the call stays open, and the agent is asked to say one short goodbye if the caller is finished, or to answer them if they are not. That goodbye then ends the call, as in the section above. This happens once for each thing the caller says. - Skysay could not judge the line (the judgement was unavailable or took longer than 2.5 seconds, the caller cut the line off, or a later stretch of the agent's speech produced no transcript): the hang-up goes ahead, as it did before this check existed.
What this means for you:
- An agent on a live engine cannot end a call without saying goodbye. If
your prompt tells the agent to end a call silently (for example on reaching a
voicemail box), have it say a short goodbye first. A refused
end_calldoes not end the call later on its own. - A hang-up can come a moment later than before. Skysay waits for the line the agent is speaking to finish, then for the judgement, which usually takes under a second and is never waited for longer than 2.5 seconds.
- An apology is not a goodbye. "I apologise for the interruption." does not end a call; "I apologise for the interruption. Goodbye." does. On these engines the standing instruction therefore tells an agent that reached the wrong person to apologise, give its one short goodbye and then end the call. Standard agents are not affected: their goodbye travels with the tool.
- After a refused
end_call, the silence recovery described under Speaking again during a goodbye applies: if nobody speaks, the agent checks in and the call then ends in the usual way.
Like the spoken-goodbye rule, this is a judgement about one spoken line, in any
language, and it can be wrong in both directions: a goodbye judged as something
else keeps the call open until the agent says goodbye again, and a line that
only sounds like a goodbye lets the hang-up through. It applies to incoming,
outgoing and browser test calls. Standard agents are not affected: there the
goodbye is the tool's message, which Skysay speaks itself.
Speaking again during a goodbye
An agent's pending hang-up can be canceled when Skysay detects the caller
speaking again. On Standard agents, this stops the pending goodbye and keeps
caller input open so the agent can answer the new request. A later legitimate
ending needs a fresh end_call request; the canceled one cannot disconnect
the continued conversation. GPT-Live 1 and Gemini Live also protect the
caller's turn during a pending close.
What counts as speaking again depends on the speech-to-text the call uses.
On a Standard phone call whose speech-to-text is Deepgram Nova-3 in English,
with min_interruption_words at its default or above
0, Skysay listens for the caller's words. Background noise on the line
that carries no words does not stop the goodbye and does not cancel the
hang-up, so a caller who says goodbye on a noisy line is still disconnected
promptly. While such noise is on the line, Skysay waits at most 1.5 seconds for
words before going ahead: once when the agent asks to end the call, and again
just before it hangs up after the goodbye, so a caller who starts saying
"wait" over the end of the goodbye is still heard. Listening noises such as
"mm-hm" are not words. Intelligible background speech, such as a television or
someone nearby talking, can still be heard as words and keep the call open.
On every other speech-to-text, and on GPT-Live 1 and Gemini Live, this protection depends on speech detection, not on recognizing a particular word such as "no"; recognized words can also cancel a Standard agent's close when the acoustic detector misses them. Missed speech may not cancel a hang-up, and noise mistaken for speech can cancel it unnecessarily.
When a hang-up is declined because the caller is speaking, the agent does not say goodbye again on its own: it answers what the caller says next, and can end the call on a later turn. Even a spoken response to the goodbye can cancel that ending attempt. On phone calls and browser tests, the cancelled attempt activates the existing silence recovery: normally, after 30 seconds of quiet the agent asks whether the caller is still there, then ends after a further 15 seconds without an answer. An already-running quiet interval can count toward that wait. Scripted workflow agents and calls that have used their three check-ins end after 45 seconds of quiet without another check-in. Each new caller turn receives a fresh quiet interval, including when a native engine delivers its caption after its reply. An active tool, transfer or other protected operation can postpone that check-in. The public homepage demo has its own session deadline instead of this silence recovery.
Cancellation cannot undo a goodbye already heard or reopen a call after disconnection. Call-length, balance and operator limits still end the call even if the caller is speaking.
The agent cannot end a call while a transfer to a human is being placed or after it has connected, and once the agent has asked to end the call it cannot start a transfer. Call-length, balance and operator limits still apply to both.
The standing call-ending instruction
Every agent that has end_call enabled receives the same instruction from
Skysay, added after your own prompt on every call:
To end the call, invoke end_call. (One sentence on where the goodbye goes, as described above for your engine.) An end_call request is a revocable proposal, not a completed hang-up. If it is refused or canceled, the call is still open: listen and answer any caller continuation, then invoke end_call again when the caller needs nothing else. Instructions to end only once mean one completed hang-up, not one attempt; they never prohibit retrying a canceled request. Do not repeat goodbyes while the caller is still telling you something. If you are calling a specific person and whoever answers says they are not that person, apologise once, share nothing about the matter, and invoke end_call. Apart from the wrong person answering, invoke end_call only when the caller has said goodbye or has confirmed they need nothing else; never end it because you cannot help with their request, and never while they are still telling you something.
On GPT-Live 1, Gemini Live and Eleven Realtime the wrong-person sentence asks for the goodbye in so many words: "... apologise once, share nothing about the matter, then give your one short goodbye and invoke end_call." On these engines the tool only ends the call after the agent's goodbye, and an apology alone is not one. Standard agents receive the sentence as quoted above.
It is written in English for every language. The agent follows it in whatever language the conversation is in, and it never becomes part of what the caller hears.
It cannot be switched off for an agent that has end_call. Turning
end_call off is how you opt out: an agent without the tool receives none of
this instruction. The instruction stays on for an agent with end_call
because it is meant to prevent four failures that show up in real calls:
- an agent that said goodbye and then kept the line open for minutes;
- an agent that kept pursuing someone who had said they were the wrong person;
- an agent that answered every follow-up question with another goodbye;
- an agent that hung up on a caller who was still explaining their problem in short sentences, often because it had decided it could not help.
So the agent is instructed to end a call only when one of these happens:
- the caller says goodbye;
- the caller confirms they need nothing else;
- the person who answers says they are not the person you are calling.
It is also instructed, when it cannot help with a request, to say so and stay
on the line. This is an instruction to the model, not a guarantee: the model
decides when to invoke end_call, and it can still request an ending earlier
than these rules allow. On live engines such a request is carried out only
after the agent's goodbye (see
above). Speech detection protects a pending close, but does
not prove the caller intended to finish. Whatever the
agent does, the call also ends when the caller hangs up or when it reaches its
maximum length.
The wrong-person rule matters most when you call people about their own accounts. Your own prompt still decides everything else about the conversation.
The instruction also reaches every language profile a language-following agent can switch to. On GPT-Live 1 it also reaches the backend model that decides when to call tools.
The tool honesty instruction
Every agent with a prompt of its own also gets a short instruction from Skysay, added after your prompt on every call and in the builder's Chat test. It names the tools the agent actually has on that call, says that these are the only actions it can take, and tells it never to say it will check, try or do something unless it calls the tool for it, nor that an action happened unless the tool's result says so. The list is the tools the agent was really given on the call, so a tool that could not be set up for that call is left out. On GPT-Live 1 the backend model reads the same list, and the list stays the same when a language-following agent switches language. It cannot be switched off. On Eleven Realtime, which limits the size of an agent's instructions, it is left out when adding it would take the instructions over that limit. It reduces, but does not prevent, an agent promising to look something up, book or transfer when it has no tool to do so: the model can still get it wrong, and it can still follow a line your prompt scripts, such as "I've marked this as urgent", when no tool did that. Agents that run a conversation flow, and SMS conversations, do not get this instruction.
When both sides go quiet
Rolling out. Ordinary silence remains in observation unless enabled for the deployment. A refused or cancelled hang-up on a phone call or browser test activates recovery for that call, so declining a hang-up cannot leave a quiet line waiting indefinitely. If an operator has explicitly disabled silence recovery, it stays disabled; the call-length and balance limits remain in force. The public homepage demo uses its own session deadline.
Sometimes the agent speaks, and then nothing more comes from either side. The caller may have put the phone down, walked away, or lost the connection in a way the network never reported. Without this rule, such a line stayed open until the call reached its maximum length. Where recovery is active (see the note above), it works like this:
- After 30 seconds of mutual silence, the agent checks in once. It asks one short question, in the language of the conversation, whether the caller is still there. On a Standard agent in English it is "Are you still there?". On GPT-Live 1 and Gemini Live the agent's own model says it.
- If the caller answers, the conversation simply continues. One word is enough, and "yes" counts. A later silence gets a new check-in.
- If nobody answers within 15 seconds after the check-in has played, the
agent says a short goodbye and the call ends. It reports
ended_reasoncaller_unresponsive.
Ordinarily the clock runs while the agent had the last word. After a cancelled hang-up, fresh caller words restart a full quiet interval even if no further model reply arrives. During continuous conversation those words keep postponing the check-in. Separately, if the caller spoke last and the agent owes a reply, the model-response safety rule can end an unresponsive engine earlier. See When the conversation engine is lost.
The clock also does not run in these cases:
- while one of the agent's tools is running;
- while a scripted workflow step is on its way;
- while a language switch is being applied;
- after a transfer to a human has connected the caller to your team;
- while the call is already ending.
Line noise without words pauses the clock for at most 20 seconds, so a noisy line cannot hold a call open for ever. Background sound on its own never counts as the caller answering.
At most three check-ins are made on one call. After that, a silence still ends the call only after the same 45 seconds, just without asking first.
Agents that run a workflow do not get this check-in. The caller's answer
to it ("yes, I'm here") would otherwise reach the workflow's current step as the
answer to that step's own question. A workflow asks its own question again
instead. See
When the caller isn't understood.
A workflow call can also end with caller_unresponsive, with reason_detail
not_understood, when the caller was heard three times in a row after a
question but no words were recognised. A silence after the caller has spoken
does not end a workflow call yet; the call's maximum length still applies.
Why 30 and 15 seconds
The values come from real calls. Across more than 2,000 silences in the middle of real conversations on Skysay:
- none lasted 45 seconds;
- one lasted 30 seconds, and the caller spoke again at 34 seconds. They would have heard one harmless "are you still there?".
Silent tails that ran on for minutes, or for a quarter of an hour, would each have ended about 45 seconds into the silence.
These values are the same for every agent and cannot be changed per agent.
Where you see it
caller_unresponsive appears wherever ended_reason does:
- on
GET /v1/calls/{call_id}and inGET /v1/callslist results; - in the terminal
call.completedwebhook; - in the campaign contact export, as the call's ending.
In the workspace, the call's transcript in Calls ends with a Call ended row, and its Closing details name this reason as Caller stopped responding.
A campaign contact whose call ended this way is treated like any other completed call. It is not retried automatically.
Retrying a contact whose call ended this way is your decision, not the platform's. The precise reason is there for your integration or campaign settings to act on.