https://retellai.com/?utm_source=discord&utm_medium=seo logo
does retell support putting call on hold
# ❓・ai-evy-support
m
@AI Evy does retell support putting call on hold?
a
Thanks for tagging me @mannankhan. I'll look through relevant sources and get back to you shortly.
### Answer Based on the available sources, Retell AI does not currently support putting callers on hold as a built-in feature. [(1) ]() A community member asked about this exact functionality, and the response was: "you can't put them on hold, try to make things as fast as possible as the longer things take the higher the likelihood of them hanging up." However, Retell AI does support on-hold music during warm transfers as part of the transfer process. [(2) ]() If you need to perform background work that takes time, the suggested workarounds are: - Optimize your processes to be as fast as possible - Consider calling the user back if tasks take longer (though they might not answer) [(1) ]()
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy what about this:- - if user says "hold on" or "please wait", reply exactly: "NO_RESPONSE_NEEDED"
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Yes, you can add prompt instructions to handle phrases like "hold on" or "please wait" by instructing the agent to respond with a specific output or remain silent. [(1) ]() You can include something like this in your agent's prompt:
Copy code
///## Guideline
If the user says "hold on", "please wait", "one moment", or similar phrases indicating they need time, reply exactly: "NO_RESPONSE_NEEDED"
This approach uses prompt engineering to control the agent's behavior when it detects these phrases. The agent will follow your instructions and output the exact phrase you specify. Important considerations: - Retell AI's turn-taking model is designed to recognize conversational cues and determine when to respond or wait. [(2) ]() , [(3) ]() - The turn-taking model combines contextual analysis with sound signals to understand whether a user is pausing or finished speaking. - However, the actual "NO_RESPONSE_NEEDED" text would still be spoken unless you handle it differently in your application logic. If your goal is to have the agent stay completely silent while the user is busy, you may want to instruct the agent to say something brief like "Sure, take your time" or "No problem, I'll wait" instead—since Retell doesn't have a native "hold" or "mute" feature for the agent.
​ To learn more, see the sources I considered: [[1] Prompt guide & examples for specific situations](https://docs.retellai.com/build/prompt-situation-guide) [[2] Retell AI's Turn-Taking Model for Seamless Calls | Retell AI](https://www.retellai.com/blog/how-retell-ais-turn-taking-model-ensures-seamless-calls) [[3] VAD vs. Turn-Taking Endpoints in Conversational AI | Retell AI](https://www.retellai.com/blog/vad-vs-turn-taking-end-point-in-conversational-ai) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy how to make agent dont speak anything until we want it to speak, without ending the call
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Based on the available sources, there isn't a built-in "mute" or "pause agent speech" feature that lets you silence the agent mid-call and resume on demand without ending the call. However, here are configuration options that may help you control when the agent speaks: ## Configure Agent to Wait for User First You can set
start_speaker
to
"user"
so the agent waits for the user to speak before responding. [(1) ]() [(2) ]() Additionally, you can use
begin_after_user_silence_ms
to control how long the agent waits for the user before speaking (if the agent is configured to wait for the user first) .
Copy code
json
{
  "start_speaker": "user",
  "begin_after_user_silence_ms": 2000
}
[(1) ]() , [(2) ]() ## Adjust Reminder Settings You can configure
reminder_max_count
to
0
to disable the agent from reminding the user when they're silent. [(3) ]() [(4) ]() You can also increase
reminder_trigger_ms
to delay how long the agent waits before prompting a silent user.
Copy code
json
{
  "reminder_max_count": 0,
  "reminder_trigger_ms": 10000
}
[(3) ]() , [(4) ]() ## Increase End-Call Silence Threshold Use
end_call_after_silence_ms
to extend how long the call stays active during silence (minimum 10,000 ms, default 600,000 ms / 10 min) . [(3) ]() [(4) ]()
Copy code
json
{
  "end_call_after_silence_ms": 600000
}
[(3) ]() , [(4) ]() These settings combined can help keep the agent quiet during periods of user silence without ending the call, but there's no documented way to programmatically mute/unmute the agent on demand during an active call.
​ To learn more, see the sources I considered: [[1] Create Retell LLM](https://docs.retellai.com/api-references/create-retell-llm) [[2] Update Retell LLM](https://docs.retellai.com/api-references/update-retell-llm) [[3] Create Voice Agent](https://docs.retellai.com/api-references/create-agent) [[4] Update Voice Agent](https://docs.retellai.com/api-references/update-agent) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy What happens if we don't respond to Retell's reminder_required? Does Retell: A) Keep waiting silently? B) Send another reminder_required after some time? C) Disconnect the call?
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Based on the available sources, here's what happens with reminders: B) Send another reminder after some time — up to the configured limit, then the call may end due to silence. The behavior is controlled by two settings: - **`reminder_trigger_ms`**: If set (in milliseconds) , will trigger a reminder to the agent to speak if the user has been silent for the specified duration after some agent speech. Default is 10,000 ms (10 s) . [(1) ]() [(2) ]() - **`reminder_max_count`**: Controls how many times the agent would remind the user when unresponsive. Default is 1 (remind once) . Set to 0 to disable reminders entirely. So if you don't respond to a reminder: 1. The agent will wait for the
reminder_trigger_ms
duration again 2. It will send another reminder, up to the
reminder_max_count
limit 3. After all reminders are exhausted and the user remains silent, the call will eventually disconnect based on
end_call_after_silence_ms
(default 600,000 ms / 10 min) The sources don't explicitly document a
reminder_required
event/webhook—if you're referring to a specific webhook or WebSocket event, I don't have information about that particular behavior in the available documentation.
​ To learn more, see the sources I considered: [[1] Create Voice Agent](https://docs.retellai.com/api-references/create-agent) [[2] Update Voice Agent](https://docs.retellai.com/api-references/update-agent) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy What happens if we don't respond to Retell's reminder_required? Does Retell: A) Keep waiting silently? B) Send another reminder_required after some time? C) Disconnect the call? I don't want to assume - do you know from experience or should I check Retell docs? Also, when we call speakText(), it uses callMetadata.responseId which gets set from the incoming event: RetellCallSocket.ts Lines 2187-2189 // Update the response Id FIRST (before any processing)callMetadata.responseId = response_id;connectedWs.set(callId, callMetadata); So if we want to send a "call is on hold" message, we'd need to make sure we still capture the response_id before returning early. Otherwise our speakText() won't have the right response ID. What's your understanding of how Retell behaves when it doesn't get a response to reminder_required?
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Based on the LLM WebSocket documentation, here's what happens with `reminder_required`: B) Retell will send another
reminder_required
after some time
— controlled by agent-level settings. The WebSocket protocol shows that Retell sends
reminder_required
events when the user has been silent for a period after agent speech. [(1) ]()
Copy code
interaction_type: "reminder_required"
The behavior is governed by these agent settings: - **`reminder_trigger_ms`**: Triggers a reminder if the user has been silent for the specified duration after agent speech. Default is 10,000 ms (10 s) . [(2) ]() - **`reminder_max_count`**: Controls how many times the agent reminds an unresponsive user. Default is 1. Set to 0 to disable reminders. After all reminders are exhausted, the call will eventually disconnect based on
end_call_after_silence_ms
(default 600,000 ms / 10 min) . **Regarding `response_id`**: You're correct that you need to capture the
response_id
from the incoming event. The documentation states that
response_id
is required in your response and "indicates which requested response this is answering." [(1) ]() When a new response is needed, Retell sends a new event with a new
response_id
, and "all previous responses will be discarded." So yes—if you want to send any response (including a "call is on hold" message) , you must include the correct
response_id
from the most recent
reminder_required
or
response_required
event.
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
​ To learn more, see the sources I considered: [[1] LLM WebSocket](https://docs.retellai.com/api-references/llm-websocket) [[2] Create Voice Agent](https://docs.retellai.com/api-references/create-agent) ​
m
@AI Evy Does Retell accept empty string as valid response content?
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Yes, Retell accepts an empty string as valid response content. [(1) ]() The documentation explicitly states that when your server sends the initial response event at connection start, you can "Set content to empty string if you want the agent to wait for user to start the conversation." This means sending a response like:
Copy code
json
{
  "response_type": "response",
  "response_id": 0,
  "content": "",
  "content_complete": true
}
This is useful for your "hold" scenario—when you receive a
reminder_required
event and want the agent to stay silent, you can respond with an empty string content to acknowledge the event without having the agent speak.
​ To learn more, see the sources I considered: [[1] LLM WebSocket](https://docs.retellai.com/api-references/llm-websocket) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy does retell support indiannumbers?
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer I don't have specific information about Indian phone number support in the available sources. The sources mention that SMS functionality is currently limited to US numbers only, but this specifically refers to SMS—not voice calls. [(1) ]() For voice call support with Indian numbers, I'd recommend checking these potentially useful sources: - [Retell AI Documentation]() - [Hire certified Retell partner]() Would you like me to try to provide a general answer, or would you prefer to reach out directly for confirmation on Indian number support for voice calls?
​ To learn more, see the sources I considered: [[1] Discord message from @immaculate_cheetah_77268 on 2025-09-04](https://discord.com/channels/1186424376300679209/1186462578310910112/1413051498996306061) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
m
@AI Evy Questions about Retell behavior during hold: Does Retell have a native "mute" or "pause" feature? Or do we need to handle everything at the application level? When we don't respond to a response_required event, what does Retell do? Does it wait indefinitely? Does it timeout? Does it keep sending the same event? If user speaks during hold and we send the reminder message, will Retell send another response_required event immediately after? This could create a loop where user speaks → we send reminder → Retell detects speech → sends response_required → we send reminder again... For the update_only events during hold: Should we also block these? Or do we need to process them to keep the connection alive? About the duplicate messages issue: When a call ends (via timeout or user action), does Retell send a final update_only event with the complete transcript? Is there a specific event that signals "call ended" from Retell's side?
a
script or a specific WebSocket event signaling "call ended." You would typically receive call end information via the webhook (
call.ended
event) rather than through the LLM WebSocket.
​ To learn more, see the sources I considered: [[1] LLM WebSocket](https://docs.retellai.com/api-references/llm-websocket) [[2] Debug call disconnection](https://docs.retellai.com/reliability/debug-call-disconnect) ​
### Answer Here are answers to your questions based on the available documentation: ## Native Mute/Pause Feature Retell does not have a native "mute" or "pause" feature—you need to handle this at the application level. [(1) ]() ## When You Don't Respond to
response_required
The documentation states that when a new response is needed, "a new event with response id will be sent, and all previous responses will be discarded." This means Retell will send a new
response_required
event with a new
response_id
when it determines another response is needed. Retell continuously assesses when it's appropriate for the agent to speak and asks for content accordingly. ## The Loop Concern Yes, this could create a loop. The documentation notes that "not all responses Retell ask for would get spoken out, cause the user might continue to speak even when Retell thought it would be agent's turn." To handle this during hold, you'd need application-level logic to track hold state and respond appropriately (e.g., with empty content or a brief acknowledgment) . ##
update_only
Events During Hold You should continue processing
update_only
events. These provide live transcript updates and turntaking information—they don't require a response from your server. If you have
auto_reconnect
set to
true
in your config, you also need to respond to
ping_pong
events every 2 seconds to keep the connection alive. Retell will close the connection if there's no ping_pong for 5 seconds. ## Call End Signaling The documentation shows various disconnection reasons like
user_hangup
,
agent_hangup
,
inactivity
, etc. [(2) ]() However, I don't have specific information in these sources about whether Retell sends a final
update_only
event with the complete tran
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy what could be solution for this? You need a way to send system messages (Hold confirm, warning, OTP prompts, etc.) with a unique response id when callMetadata.responseId is not yet available — instead of always falling back to 0.
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Based on the LLM WebSocket documentation, there are two approaches to send messages when you don't have a
response_id
from Retell yet: ## 1. Use the Agent Interrupt Event The
agent_interrupt
event allows you to jump into the conversation and speak content immediately—**without needing a `response_id`** from a
response_required
or
reminder_required
event. [(1) ]()
Copy code
json
{
  "response_type": "agent_interrupt",
  "content": "Your call is now on hold. Please wait.",
  "content_complete": true
}
This event "interrupts both agent and user" and lets you speak content immediately. ## 2. Always Capture the Latest
response_id
The documentation states that when a new response is needed, "a new event with response id will be sent, and all previous responses will be discarded." For your application logic: - Store the
response_id
from every
response_required
and
reminder_required
event you receive - Use that stored ID when sending system messages - If no
response_id
has been received yet (call just started) , use the
agent_interrupt
event instead ## Recommended Pattern - **At call start or when no
response_id
exists**: Use
agent_interrupt
for system messages - **After receiving any `response_required`/`reminder_required`**: Use the standard
response
event with the captured
response_id
The
agent_interrupt
event is specifically designed for cases where you need to proactively send content without waiting for Retell to request it.
​ To learn more, see the sources I considered: [[1] LLM WebSocket](https://docs.retellai.com/api-references/llm-websocket) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy can you comment if this is correct/wrong? What’s happening At hold expiry you’re calling: ts Copy Code void this.handleInactivityTimeout(...) And handleInactivityTimeout() still uses speakText() to send the final timeout message: await RetellCallSocket.speakText({ endCall: true, contentComplete: true, ... }) (see [[file:chatteron.chatteron:services/web/src/socket.io/RetellCallSocket.ts:1565-1573]]) That means the final hold-timeout message is being sent as a normal “response” payload (response_id-based), out-of-band (not in response to a response_required turn). Retell doesn’t like that in this scenario and you end up with: Retell dashboard: Error_llm_websocket_open You see hangup logs (“Hanging up the call due to no activity”) but no final message spoken, because the WS message likely caused Retell to terminate due to protocol/state expectations. The reason warning works is: you already switched warning to agent_interrupt. So the fix is: Hold expiry must also use agent_interrupt, not the normal response flow.
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Your analysis appears correct based on the LLM WebSocket documentation. ## Why the
response
event fails in this scenario The
response
event requires a valid
response_id
that "indicates which requested response this is answering." [(1) ]() This is designed to respond to
response_required
or
reminder_required
events from Retell. When you send a
response
event out-of-band (not in direct reply to a Retell request) , Retell may not be expecting it, which can cause protocol issues like
Error_llm_websocket_open
. ## Why
agent_interrupt
is the correct approach The
agent_interrupt
event is specifically designed for your use case—it allows you to "jump in the conversation and speak something immediately" without needing a
response_id
from a prior Retell request.
Copy code
json
{
  "response_type": "agent_interrupt",
  "interrupt_id": 1,
  "content": "Your hold time has expired. Goodbye.",
  "content_complete": true,
  "end_call": true
}
Key differences: -
agent_interrupt
uses
interrupt_id
(a unique ID you maintain on your server) instead of
response_id
- It "will stop the agent speech if the agent is speaking, or it will interrupt the user if the user is speaking" - It supports
end_call: true
to end the call after the content is spoken ## Recommendation Yes, switch your hold expiry message to use
agent_interrupt
with
end_call: true
, just like you did for the warning message.
​ To learn more, see the sources I considered: [[1] LLM WebSocket](https://docs.retellai.com/api-references/llm-websocket) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.
m
@AI Evy is this also correct? Why the old 20s inactivity timeout worked (before Hold existed) In the original flow, when a call is active (not on hold), Retell is in the normal “LLM response” lifecycle. When your 20s inactivity timer fires, handleInactivityTimeout() sends the timeout message using speakText(), which sends a normal response payload (response_id, content_complete, end_call): handleInactivityTimeout → speakText(endCall: true, contentComplete: true, text: INACTIVITY_MESSAGE) [[file:chatteron.chatteron:services/web/src/socket.io/RetellCallSocket.ts:1565-1573]] speakText uses callMetadata.responseId || 0 and sends a RetellResponse via ws.send [[file:chatteron.chatteron:services/web/src/socket.io/RetellCallSocket.ts:1164-1188]] That’s the path Retell expects for “regular agent speech”. Why it breaks now only in the Hold-expiry case Your hold warning/hold confirmation are now sent via agent_interrupt (which is correct). Logs confirm: Hold confirm: Sent agent_interrupt Warning: Sent agent_interrupt Then at expiry you still call handleInactivityTimeout() from the hold monitor branch: ts Copy Code void this.handleInactivityTimeout(...) That means at T-0 (hold expiry), the code sends the final message via speakText() (a normal response payload) even though it is out-of-band (i.e., not tied to a current response_required/reminder_required turn). That mismatch is what Retell is flagging as: Disconnection Reason Error_llm_websocket_open In short: Hold confirm/warning: agent_interrupt ✅ (Retell-approved for proactive speech) Hold expiry: response payload via speakText(endCall: true) ❌ (out-of-band, Retell may reject/terminate) That explains why the warning plays but the final timeout speech doesn’t.
a
Thanks for the follow-up, @mannankhan. I'll get back to you soon.
### Answer Your analysis is correct based on the LLM WebSocket documentation. ## Why the normal
response
event works during active calls During normal call flow, Retell sends
response_required
events when it determines the agent should speak. Your server responds with a
response
event that includes the
response_id
from that request. [(1) ]() The documentation states: "When a new response is needed, a new event with response id will be sent, and all previous responses will be discarded." So when your 20s inactivity timer fires during a normal active call, there's likely a recent
response_id
available from the ongoing conversation lifecycle, making the
response
payload valid. ## Why it breaks during hold expiry The
agent_interrupt
event is specifically designed to "jump in conversation and speak content immediately, interrupts both agent and user." Key distinction: - **`response` event**: Requires a valid
response_id
that "indicates which requested response this is answering" - **`agent_interrupt` event**: Uses
interrupt_id
(a unique ID you maintain on your server) and doesn't require a prior Retell request During hold, you're not in the normal response lifecycle—Retell isn't actively requesting responses. Sending a
response
payload out-of-band (without a corresponding
response_required
turn) causes the protocol mismatch. ## The fix Use
agent_interrupt
with
end_call: true
for hold expiry, same as your warning message. [(2) ]()
​ To learn more, see the sources I considered: [[1] LLM WebSocket](https://docs.retellai.com/api-references/llm-websocket) [[2] I don't understand how Agent Interrupt Event works with Custom LLM](https://discord.com/channels/1186424376300679209/1354817107799576795) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.