punk8357
02/02/2026, 3:29 PMAI Evy
02/02/2026, 3:29 PMAI Evy
02/02/2026, 3:29 PM{{dynamic_variable}} === value in your transition prompt. [(2) ]()AI Evy
02/02/2026, 3:29 PMAI Evy
02/02/2026, 3:29 PMpunk8357
02/02/2026, 3:32 PMpunk8357
02/02/2026, 3:32 PMAI Evy
02/02/2026, 3:32 PMAI Evy
02/02/2026, 3:33 PM{{dynamic_variable}} == "value") are recommended when you want to branch based solely on dynamic variable values. [(1) ]() They're deterministic—if the condition matches, the transition happens. Prompt-based conditions rely on the LLM to interpret the condition, which can introduce variability.
Note that ==, Contains, Not Contains, and Not Equal are string comparisons and don't require numerical input. Other comparison operators require numerical input and will always evaluate to false if the input is not a number.
Setting Dynamic Variables from Function Results:
You need to explicitly configure the function to extract and store variables. Your agents can extract and store dynamic variables mid-conversation using the Extract Variables feature. [(2) ]() For custom functions, you can set response variables from the function result.
In a conversation flow, you would configure the function node to map the function response to dynamic variables. The variables won't be automatically set just from calling a function—you need to specify which parts of the response should be stored as dynamic variables.
Checking if a Variable Exists:
You can also use these equation conditions to check whether a variable is set: [(1) ]()
- {{variable_name}} exists — Returns true if the variable is defined and has a value
- {{variable_name}} does not exists — Returns true if the variable is undefined or has no valueAI Evy
02/02/2026, 3:33 PMAI Evy
02/02/2026, 3:33 PMpunk8357
02/02/2026, 3:34 PMAI Evy
02/02/2026, 3:34 PMAI Evy
02/02/2026, 3:35 PMpython
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from retell import Retell
retell = Retell(api_key=os.environ["RETELL_API_KEY"])
@app.post("/check-weather")
async def check-weather(request: Request) :
try:
post_data = await request.json()
valid_signature = retell.verify(
json.dumps(post_data, separators=(",", ":") , ensure_ascii=False) ,
api_key=str(os.environ["RETELL_API_KEY"]) ,
signature=str(request.headers.get("X-Retell-Signature") ) ,
)
if not valid_signature:
return JSONResponse(status_code=401, content={"message": "Unauthorized"})
args = post_data["args"]
if args["city"] == "New York":
return JSONResponse(status_code=200, content={"result": "25f and sunny"})
else:
return JSONResponse(status_code=200, content={"result": "20f and cloudy"})
except Exception as err:
print(f"Error in webhook: {err}")
return JSONResponse(status_code=500, content={"message": "Internal Server Error"})
The key step is configuring the response variable mapping in the function node UI to specify which part of your backend's JSON response should be stored as which dynamic variable.AI Evy
02/02/2026, 3:35 PMAI Evy
02/02/2026, 3:35 PMjson
{
"properties": {
"user": {
"name": "John Doe",
"age": 26
}
}
}
You can extract the user's name from the response and reference it later using {{user_name}}.
3. Your Backend Response
Your backend should return a response with status code 200-299. The response can be a string, buffer, JSON object, or blob—all formats will be converted to string before processing.
*4. Verify Requests (Optional) *
To verify requests are from Retell, check the X-Retell-Signature header:AI Evy
02/02/2026, 3:35 PMpunk8357
02/02/2026, 3:36 PMAI Evy
02/02/2026, 3:36 PMAI Evy
02/02/2026, 3:36 PMpatient as an array, you'd use patient[0].providerNo rather than just patient.providerNo. [(2) ]()
- Use the variable name directly (like {{make}}) rather than nested notation like scheduling_info_extraction.make when referencing extracted variables in subsequent function calls. [(3) ]()
Once configured, you can reference the extracted variable using {{user_name}} syntax in prompts or transition conditions throughout your conversation flow. [(4) ]()
If you need to pass dynamic variables when creating a call programmatically, you can use retell_llm_dynamic_variables in your API request:
javascript
const webCallResponse = await client.call.createWebCall({
agent_id: 'oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD',
}) ;
[(5) ]()
But the response variable extraction mapping itself is done in the function node configuration within the Conversation Flow editor, not through the API.AI Evy
02/02/2026, 3:36 PMAI Evy
02/02/2026, 3:36 PMpunk8357
02/02/2026, 3:37 PMAI Evy
02/02/2026, 3:37 PMAI Evy
02/02/2026, 3:37 PMretell_llm_dynamic_variables
- Your backend can return data that gets extracted based on the UI-configured mapping
If you need fully programmatic agent configuration, you may want to check the [Retell AI API references]() for agent creation/update endpoints, or reach out to support for guidance on whether this capability exists or is planned.AI Evy
02/02/2026, 3:37 PMAI Evy
02/02/2026, 3:37 PMpunk8357
02/02/2026, 3:43 PMAI Evy
02/02/2026, 3:43 PMAI Evy
02/02/2026, 3:43 PM{{user_name}}, you need to configure the mapping in the function node settings.
Without that explicit configuration, the LLM can reference the function result in its immediate response, but the value won't be persisted as a dynamic variable for use in transition conditions or later nodes.AI Evy
02/02/2026, 3:43 PMAI Evy
02/02/2026, 3:43 PMpunk8357
02/02/2026, 3:44 PMAI Evy
02/02/2026, 3:44 PMAI Evy
02/02/2026, 3:45 PMtools field that accepts an array of tool/function configurations. [(1) ]()
The API response structure shows:
json
[
{
"type": "custom",
"name": "get_customer_info",
"description": "Get customer information from database",
"tool_id": "tool_001",
"url": "<https://api.example.com/customer%22,>
"method": "GET"
}
]
So yes—you could configure a conversation flow in the UI, then use the API to retrieve the conversation flow structure and inspect how the response variable extraction is formatted. The conversation flow API includes components for local components embedded within the flow and tools for the function configurations.
However, the sources I have don't show the exact schema for response variable extraction within the tool/function configuration. Your approach of setting it up in the UI first and then extracting the structure via API to see the format is a practical way to reverse-engineer the schema.
Check the [Create Conversation Flow]() and related GET endpoints to retrieve an existing flow's full configuration.AI Evy
02/02/2026, 3:45 PMAI Evy
02/02/2026, 3:45 PMpunk8357
02/02/2026, 3:48 PMAI Evy
02/02/2026, 3:48 PMAI Evy
02/02/2026, 3:48 PMtools or components arrays.
Would you like a general answer based on typical API patterns, or would you prefer to reach out to Retell support for the exact schema?AI Evy
02/02/2026, 3:48 PMAI Evy
02/02/2026, 3:48 PMpunk8357
02/02/2026, 3:50 PMAI Evy
02/02/2026, 3:50 PMAI Evy
02/02/2026, 3:50 PMget_user_details)
- **HTTP Method**: Choose GET, POST, PATCH, PUT, or DELETE
- **Endpoint URL**: Add the URL where Retell will send the request
- Request headers (optional) : Define custom headers with static or dynamic variable values
- Query parameters (optional) : Define query parameters to include in the request URL
- **Parameters**: Define using JSON schema format or JSON form (only for POST, PATCH, PUT)
- Response variables (optional) : Extract values from the API response and save them as dynamic variables
4. Configure node settings
[(1) ]()
- **Speak During Execution**: Instructions for what the agent says while the function executes
- **Wait for Result**: When enabled, the agent waits for the function to finish before transitioning
5. Connect the node
[(2) ]()
Click and hold the circle to start a line that connects the node to other nodes.AI Evy
02/02/2026, 3:50 PMAI Evy
02/02/2026, 3:50 PMpunk8357
02/02/2026, 4:05 PMAI Evy
02/02/2026, 4:05 PMAI Evy
02/02/2026, 4:06 PM{{ai_enabled}} == "true"
Note that ==, Contains, Not Contains, and Not Equal are **string comparisons**—they do not require numerical input.
So if your variable stores the value as the string "true" or "false", use the string comparison format above.
You can also check if the variable exists using:
{{ai_enabled}} exists
If you need to branch on both outcomes, you'd create separate transition conditions like:
{{ai_enabled}} == "true"
{{ai_enabled}} == "false"
Make sure the value you're comparing matches exactly what your function returns (e.g., "true" as a string vs true as a boolean may behave differently depending on how it's stored) .AI Evy
02/02/2026, 4:06 PMAI Evy
02/02/2026, 4:06 PMpunk8357
02/02/2026, 4:07 PMAI Evy
02/02/2026, 4:07 PMAI Evy
02/02/2026, 4:07 PM==, Contains, Not Contains, and Not Equal. [(1) ]()
If your function returns a boolean (`true`/`false` without quotes) , it will likely be converted to a string when stored as a dynamic variable. You should still use the string comparison format:
{{ai_enabled}} == "true"
{{ai_enabled}} == "false"
Alternatively, you can use the exists check if you only need to verify the variable is set:
{{ai_enabled}} exists
If you're experiencing issues with the comparison not working as expected, try logging or displaying the variable value (using {{ai_enabled}} in a static sentence) to confirm exactly how it's being stored—this can help you determine whether it's stored as "true", "True", true, or another format. [(2) ]()
The safest approach is to ensure your backend returns the value as a string ("true" or "false") rather than a boolean, since the equation conditions are designed for string comparisons.AI Evy
02/02/2026, 4:07 PMAI Evy
02/02/2026, 4:07 PMpunk8357
02/02/2026, 4:08 PMAI Evy
02/02/2026, 4:08 PMAI Evy
02/02/2026, 4:08 PM= in the UI is fine. The documentation shows the syntax using == in text examples, but the UI may display it as = or "equals"—they represent the same equality comparison. [(1) ]()
The key point is that == (or = in the UI) is a string comparison. So for your boolean variable, use:
{{ai_enabled}} == "true"
Or in the UI, select the equals condition and compare against the string "true".AI Evy
02/02/2026, 4:08 PMAI Evy
02/02/2026, 4:08 PMpunk8357
02/02/2026, 4:11 PMAI Evy
02/02/2026, 4:11 PMAI Evy
02/02/2026, 4:11 PM{{ai_enabled}} == "true"
{{ai_enabled}} == "false"
Each condition points to a different destination node. Equation conditions are evaluated first (before prompt conditions) , and the agent travels on the first condition that evaluates to true.
To set this up:
1. Remove the direct transitions from your prior node to the two destination nodes
2. Connect your prior node to the function node instead
3. On the function node, add transition conditions using the "+" button
4. Create separate equation conditions for each branch, each pointing to the appropriate destination node , [(2) ]()AI Evy
02/02/2026, 4:11 PMAI Evy
02/02/2026, 4:11 PMpunk8357
02/02/2026, 4:14 PMAI Evy
02/02/2026, 4:14 PMAI Evy
02/02/2026, 4:14 PMAI Evy
02/02/2026, 4:14 PMAI Evy
02/02/2026, 4:14 PMpunk8357
02/02/2026, 4:19 PMAI Evy
02/02/2026, 4:19 PMAI Evy
02/02/2026, 4:19 PMAI Evy
02/02/2026, 4:19 PMAI Evy
02/02/2026, 4:19 PMpunk8357
02/02/2026, 5:07 PMAI Evy
02/02/2026, 5:07 PMAI Evy
02/02/2026, 5:07 PMconversation_flow.create() endpoint does not work as expected—the tools parameter is accepted but the tools don't actually get created. [(1) ]()
The workaround is to use the Update Conversation Flow API instead:
1. First, create the conversation flow without tools
2. Then use the update endpoint to add the tools
Here's the tool structure format from the Create Conversation Flow API documentation: [(2) ]()
json
[
{
"type": "custom",
"name": "get_customer_info",
"description": "Get customer information from database",
"tool_id": "tool_001",
"url": "<https://api.example.com/customer%22,>
"method": "GET"
}
]
The tools array accepts objects with these fields:
- `type`: e.g., "custom"
- `name`: unique function name
- `description`: what the function does
- `tool_id`: identifier for the tool
- `url`: endpoint URL
- `method`: HTTP method (GET, POST, PATCH, PUT, DELETE)
For the update endpoint, see: [Update Conversation Flow]() [(1) ]()AI Evy
02/02/2026, 5:07 PMAI Evy
02/02/2026, 5:07 PMpunk8357
02/02/2026, 5:09 PMAI Evy
02/02/2026, 5:09 PMAI Evy
02/02/2026, 5:09 PMtool_id after creating a tool, you can use the Get Conversation Flow API endpoint to retrieve the full conversation flow structure, which includes the tools array with their IDs. [(1) ]()
javascript
import Retell from 'retell-sdk';
const client = new Retell({
apiKey: 'YOUR_RETELL_API_KEY',
}) ;
const conversationFlowResponse = await client.conversationFlow.retrieve('conversation_flow_id') ;
console.log(conversationFlowResponse.conversation_flow_id) ;
The response includes the tools array with each tool's configuration: [(2) ]() , [(1) ]()
json
{
"type": "custom",
"name": "get_customer_info",
"description": "Get customer information from database",
"tool_id": "tool_001",
"url": "<https://api.example.com/customer%22,>
"method": "GET"
}
[(2) ]()
Workflow:
1. Create or update your conversation flow with the tool via the API
2. Call the Get Conversation Flow endpoint with your conversation_flow_id [(1) ]()
3. Parse the response's tools array to find the tool_id for each tool
The tool_id from this response is what you'd reference when configuring function nodes.AI Evy
02/02/2026, 5:09 PMAI Evy
02/02/2026, 5:09 PMpunk8357
02/02/2026, 5:24 PMAI Evy
02/02/2026, 5:24 PMAI Evy
02/02/2026, 5:25 PMmodel_choice is properly configured in your API request — this is a required field [(4) ]()
- Ensure your nodes array has valid node configurations with proper instruction objects
- Check that start_speaker is set to either "user" or "agent"
- Retrieve your conversation flow using the Get endpoint to verify all settings were saved correctly [(5) ]()
Required fields when creating via API:
- model_choice (required)
- start_speaker (required)
- nodes array (required) [(4) ]()
Try refreshing the page and creating a new test chat, and verify your flow structure matches the expected schema.AI Evy
02/02/2026, 5:25 PMAI Evy
02/02/2026, 5:25 PMpunk8357
02/02/2026, 5:52 PMAI Evy
02/02/2026, 5:52 PMAI Evy
02/02/2026, 5:53 PMstart_node_id parameter when creating or updating your conversation flow. [(1) ]()
This parameter specifies which node the flow begins with—effectively connecting the purple "begin" tag to your first node.
Here's an example from the Create Conversation Flow API:
javascript
import Retell from 'retell-sdk';
const client = new Retell({
apiKey: 'YOUR_RETELL_API_KEY',
}) ;
const conversationFlowResponse = await client.conversationFlow.create({
model_choice: { model: 'gpt-4.1', type: 'cascading' },
nodes: [
{
id: 'start',
instruction: { text: 'Greet the customer and ask how you can help them.', type: 'prompt' },
type: 'conversation',
},
],
start_speaker: 'agent',
}) ;
Key points:
- Set start_node_id to match the id of your first node (e.g., "start")
- The start_node_id field is described as "ID of the start node in the conversation flow"
- You can also set begin_tag_display_position to control where the begin tag appears visually in the frontend
If you've already created the flow without setting start_node_id, you can update it using the Update Conversation Flow endpoint and include the start_node_id parameter pointing to your first node's ID.AI Evy
02/02/2026, 5:53 PMAI Evy
02/02/2026, 5:53 PMpunk8357
02/02/2026, 6:05 PMAI Evy
02/02/2026, 6:05 PMAI Evy
02/02/2026, 6:05 PMX-Retell-Signature header that you can use to verify the request is from Retell.
Here's how verification works:
javascript
import { Retell } from "retell-sdk";
this.app.post("/check-weather", async (req: Request, res: Response) => {
if (
!Retell.verify(
JSON.stringify(req.body) ,
process.env.RETELL_API_KEY,
req.headers["x-retell-signature"] as string,
)
) {
console.error("Invalid signature") ;
return;
}
// ... handle request
}) ;
Summary:
- **Headers**: Optional—use only if your endpoint requires authentication or custom headers
- **Query parameters**: Optional—use only if your endpoint needs them
- **x-api-key**: Not required in the function config. Use X-Retell-Signature verification on your server side instead
You can also allowlist Retell's IP address (100.20.5.228) to secure your server from public network access.AI Evy
02/02/2026, 6:05 PMAI Evy
02/02/2026, 6:05 PMpunk8357
02/02/2026, 6:06 PMAI Evy
02/02/2026, 6:06 PMAI Evy
02/02/2026, 6:06 PMX-Retell-Signature is **optional**—it's a security measure you can choose to implement, not a requirement for your function to work. [(1) ]()
The X-Retell-Signature header is provided by Retell so you can verify that incoming requests to your endpoint are actually from Retell.
Your options:
1. Skip verification entirely — Your function will still work; you just won't have proof the request came from Retell
2. Use signature verification — Verify using the X-Retell-Signature header with your Retell API key
3. IP allowlisting — Alternatively, you can secure your server by only allowlisting Retell's IP address: 100.20.5.228
If you do want to implement verification, here's the pattern:
javascript
import { Retell } from "retell-sdk";
if (
!Retell.verify(
JSON.stringify(req.body) ,
process.env.RETELL_API_KEY,
req.headers["x-retell-signature"] as string,
)
) {
console.error("Invalid signature") ;
return;
}
For a simple setup or testing, you can skip verification. For production, signature verification or IP allowlisting is recommended for security.AI Evy
02/02/2026, 6:06 PMAI Evy
02/02/2026, 6:06 PMpunk8357
02/02/2026, 6:08 PMAI Evy
02/02/2026, 6:08 PMAI Evy
02/02/2026, 6:08 PMagent_id does not change when you publish. The agent_id remains the same unique identifier for your agent. [(1) ]()
What changes is the version number. Each agent has a version field that increments when you publish new versions.
From the Get Agent Versions API response:
json
{
"agent_id": "oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD",
"version": 0,
"is_published": false
}
The agent_id stays constant across all versions of your agent—only the version integer changes.
Note from community feedback: If you're seeing calls go to a different agent than expected, check whether the from_number is assigned to a specific agent in the dashboard—that assignment can override the agent_id you pass in API params. [(2) ]()AI Evy
02/02/2026, 6:08 PMAI Evy
02/02/2026, 6:08 PMpunk8357
02/02/2026, 6:12 PMAI Evy
02/02/2026, 6:12 PMAI Evy
02/02/2026, 6:12 PMwss:// prefix
- HTTP endpoints: Use ws:// prefix
The changelog confirms custom functions were enhanced to support all HTTP methods (GET, POST, PUT, PATCH, DELETE) along with custom headers and query parameters. [(5) ]()
If you're still experiencing issues, add logging to verify what's actually being received at your endpoint.AI Evy
02/02/2026, 6:12 PMAI Evy
02/02/2026, 6:12 PMpunk8357
02/02/2026, 6:16 PMAI Evy
02/02/2026, 6:16 PMAI Evy
02/02/2026, 6:16 PMAI Evy
02/02/2026, 6:16 PMAI Evy
02/02/2026, 6:16 PMpunk8357
02/02/2026, 6:26 PMAI Evy
02/02/2026, 6:26 PMAI Evy
02/02/2026, 6:27 PMwait for result is turned on, the agent will transition once the function result is ready and the agent is done talking (if "speak during execution" is enabled)
- If wait for result is turned off, the agent transitions immediately after the function gets invoked
2. Check your transition conditions
Since the function node takes function result into consideration for transition timing, you can write your transition condition to be based on the function result.
Make sure you have edges connected from the function node to the next node(s) with appropriate transition conditions.
3. Add a conversation node after the function node
The function node is not intended for having a conversation with the user. To tell the user the result, you need to attach a conversation node to the function node.
You can create different conversation nodes for different function results, so that it can engage the user in different ways when function result varies.
4. Debugging tips
- Review your transition conditions to ensure they precisely match your intended triggers
[(2) ]()
- Add transition finetune examples to help the model understand your expectations
- Check if the LLM is failing to recognize the trigger condition
[(3) ]()
If transitions still aren't working, try making your transition conditions more flexible and general.
[(2) ]()AI Evy
02/02/2026, 6:27 PMAI Evy
02/02/2026, 6:27 PMpunk8357
02/02/2026, 6:28 PMAI Evy
02/02/2026, 6:28 PMAI Evy
02/02/2026, 6:28 PM==, Contains, Not Contains, and Not Equal are string comparisons — they do not require numerical input
- Other comparison operators (>, <, etc.) require numerical input and will always evaluate to false if the input is not a number
So if you're returning booleans and trying to use them in equation conditions, you may need to:
1. Return strings instead (e.g., "true" or "false") and use string comparison:
{{result}} == "true"
2. Use prompt-based conditions instead of equations — these let the LLM evaluate the condition based on context. Example prompt conditions:
- CRM lookup returned successful result
- Function returned a positive result
Transition setup from function nodes:
You can write transition conditions based on the function result. Create different conversation nodes for different function results so the agent can engage users differently depending on what the function returns. [(1) ]()
If your condition logic is based on dynamic variables from the function result, use equation conditions. If you need the LLM to interpret the result semantically, use prompt conditions. [(2) ]()AI Evy
02/02/2026, 6:28 PMAI Evy
02/02/2026, 6:28 PMpunk8357
02/02/2026, 6:35 PMAI Evy
02/02/2026, 6:35 PMAI Evy
02/02/2026, 6:35 PM{"ai_enabled":"true",...}, but for an equation condition like {{ai_enabled}} == "true" to work, ai_enabled needs to exist as a dynamic variable that the equation can reference.
Two options to fix this:
1. Use a prompt-based condition instead of an equation — Prompt conditions can evaluate information learned during the call (like function results) without needing it stored as a dynamic variable first. Example:
- Function returned ai_enabled as true
- The function result indicates AI is enabled
2. Extract the function result into a dynamic variable — Use an Extract DV Node after your function node to store ai_enabled as a dynamic variable, then your equation condition {{ai_enabled}} == "true" should work. [(2) ]()
The key distinction: equation conditions only work with variables passed in as dynamic variables, while prompt conditions can reference information extracted by the LLM during the call. [(1) ]()AI Evy
02/02/2026, 6:35 PMAI Evy
02/02/2026, 6:35 PMpunk8357
02/02/2026, 6:36 PMAI Evy
02/02/2026, 6:36 PMAI Evy
02/02/2026, 6:37 PMwait for result turned on, the agent will transition once the function result is ready. [(1) ]()
So the sequence is:
1. Function node executes and returns {"ai_enabled":"true",...}
2. Transition to an Extract DV Node (you can use a simple prompt condition like "when function completes")
3. The Extract DV Node extracts ai_enabled from the conversation context and stores it as a dynamic variable [(2) ]()
4. Transition from the Extract DV Node to your next node using the equation condition {{ai_enabled}} == "true" [(3) ]()
The function result is included in the agent's context, so the Extract DV Node can access it. [(4) ]() You're not extracting it before the function runs—you're extracting it from the result that's now in context after the function completes.
Alternatively, if you want to skip the extra node, use a prompt-based condition directly on the function node instead of an equation. Prompt conditions can evaluate information learned during the call (like function results) without needing it stored as a dynamic variable first. [(3) ]()AI Evy
02/02/2026, 6:37 PMAI Evy
02/02/2026, 6:37 PMpunk8357
02/02/2026, 6:41 PMAI Evy
02/02/2026, 6:41 PMAI Evy
02/02/2026, 6:42 PM{{variable}} exists directly after extraction, the condition may evaluate before the variable populates, causing the node to get stuck or loop. [(2) ]()
Recommended fix — use a Logic Split Node:
Instead of putting equation conditions directly on your Extract DV Node:
1. Extract DV Node → transition with a simple prompt condition (e.g., "when extraction is complete" or no condition)
2. Logic Split Node → place your equation conditions here (e.g., {{ai_enabled}} == "true")
3. Route from the Logic Split Node to your different destination nodes
The Logic Split Node transitions immediately and evaluates without waiting for user input, which breaks the stuck/loop pattern.
Alternative:
Community feedback suggests that if you imported your agent from a sample template, the sample may have incorrect configuration that causes this behavior. Try creating a new agent from scratch rather than modifying an imported one. [(1) ]()AI Evy
02/02/2026, 6:42 PMAI Evy
02/02/2026, 6:42 PMpunk8357
02/02/2026, 6:43 PMAI Evy
02/02/2026, 6:43 PMAI Evy
02/02/2026, 6:43 PM{{ or }} when configuring the variable. [(1) ]()
When creating a variable in the Extract DV Node, you fill in:
- Variable Name – A short name to reference this variable (e.g., ai_enabled)
- Description – A brief explanation of what this value should be
- Variable Type – Choose from Text, Number, Enum, or Boolean
The {{ }} syntax is used **elsewhere**—specifically in transition conditions (equation type) or when referencing the variable in prompts, custom functions, or other nodes after extraction. [(2) ]()
Example:
- In the Extract DV Node: just enter ai_enabled as the variable name (no brackets)
- In a transition condition (equation) : use {{ai_enabled}} == "true"
- In a custom function parameter: use {{ai_enabled}} to reference the extracted value [(3) ]()
Important note from community feedback: When referencing variables in custom functions, use the variable name directly like {{make}}, not dot notation like {{scheduling_info_extraction.make}}.AI Evy
02/02/2026, 6:43 PMAI Evy
02/02/2026, 6:43 PMpunk8357
02/02/2026, 7:05 PMAI Evy
02/02/2026, 7:05 PMAI Evy
02/02/2026, 7:05 PM{{ai_enabled}} == "true") , you must extract it into a dynamic variable first using an Extract DV Node. [(2) ]()
In short:
- For prompt-based conditions or speaking the result: The agent remembers the function result—no extraction needed
- For equation conditions: You need to extract the value into a dynamic variable, because equation conditions only work with variables passed in or explicitly stored as dynamic variables
So it depends on how you want to use the data. If you're routing based on equation logic, extract it. If you're just having the agent respond based on the result or using prompt conditions, the context is already available.AI Evy
02/02/2026, 7:05 PMAI Evy
02/02/2026, 7:05 PMpunk8357
02/02/2026, 7:46 PMAI Evy
02/02/2026, 7:46 PMAI Evy
02/02/2026, 7:46 PM> — greater than (requires numerical input)
- < — less than (requires numerical input)
- == — equals (string comparison, does not require numerical input)
- != — not equal (string comparison)
String Operators:
- CONTAINS — checks if a string contains a value
- NOT CONTAINS — checks if a string does not contain a value
Existence Operators:
- exists — returns true if the variable is defined and has a value
- does not exists — returns true if the variable is undefined or has no value
Logical Operators:
- AND — both conditions must be true
- OR — at least one condition must be true
Example syntax:
{{current_time}} > 9 AND {{current_time}} < 18
{{user_location}} == "New York"
{{user_location}} != "New York"
"New York, Los Angeles" CONTAINS {{user_location}}
"New York, Los Angeles" NOT CONTAINS {{user_location}}
{{user_age}} < 18 OR {{user_location}} == "New York"
{{name}} exists
{{user_email}} exists
{{user_phone}} not exists
Important: The ==, Contains, Not Contains, and Not Equal operators are **string comparisons**—they do not require numerical input. The other comparison operators (>, <) require numerical input and will always evaluate to false if the input is not a number.AI Evy
02/02/2026, 7:46 PMAI Evy
02/02/2026, 7:46 PMpunk8357
02/02/2026, 7:53 PMAI Evy
02/02/2026, 7:53 PMAI Evy
02/02/2026, 7:53 PMskip response turned on) before the Call Transfer Node.
This setup ensures:
1. The Conversation Node handles any pre-transfer message
2. The Call Transfer Node executes silentlyAI Evy
02/02/2026, 7:53 PMAI Evy
02/02/2026, 7:53 PMpunk8357
02/02/2026, 7:54 PMAI Evy
02/02/2026, 7:54 PMAI Evy
02/02/2026, 7:54 PMLet me check that for you. to say while the function is being executed. You can choose between Prompt and Static Sentence.
However, the available sources don't include the specific API field names or parameters for enabling/disabling "Speak During Execution" on a transfer node programmatically. The documentation describes the dashboard UI behavior but doesn't show the corresponding API schema.
Check out these potentially useful sources for API details:
- [Call Transfer Node]()
- [Agent Transfer Node]()
You may also want to check the API reference documentation for conversation flow nodes, or I could try to provide a general answer based on common API patterns if you'd like.AI Evy
02/02/2026, 7:54 PMAI Evy
02/02/2026, 7:54 PMpunk8357
02/02/2026, 8:15 PMAI Evy
02/02/2026, 8:15 PMAI Evy
02/02/2026, 8:15 PMAI Evy
02/02/2026, 8:15 PMAI Evy
02/02/2026, 8:15 PMpunk8357
02/03/2026, 10:27 PMAI Evy
02/03/2026, 10:27 PMAI Evy
02/03/2026, 10:27 PMAI Evy
02/03/2026, 10:27 PMAI Evy
02/03/2026, 10:27 PMpunk8357
02/03/2026, 10:29 PMAI Evy
02/03/2026, 10:29 PMAI Evy
02/03/2026, 10:29 PMgeneral_tools (available across all states) or within specific states[].tools arrays. [(2) ]() The LLM autonomously decides when to call functions based on the prompt and conversation flow.
- **Conversation flow agents**: You explicitly control when functions execute by creating dedicated Function Nodes and defining transition conditions to reach them.
For multi-prompt agents via API, you configure tools like this in the LLM object:
json
"general_tools": [
{
"type": "end_call",
"name": "end_call",
"description": "End the call with user."
}
]
State-specific tools go in the states[].tools array, and state transitions are defined via edges within each state.AI Evy
02/03/2026, 10:29 PMAI Evy
02/03/2026, 10:29 PMpunk8357
02/03/2026, 10:30 PMAI Evy
02/03/2026, 10:30 PMAI Evy
02/03/2026, 10:30 PMgeneral_tools or state-specific tools arrays) , and the LLM decides when to call them based on conversation context. [(3) ]() You specify explicit tool calling instructions in your prompt to guide when functions should be triggered.
Summary:
- Conversation Flow agents → use Function Nodes (and other node types)
- Multi-prompt agents → define tools in prompts; no nodes involvedAI Evy
02/03/2026, 10:30 PMAI Evy
02/03/2026, 10:30 PMpunk8357
02/03/2026, 10:31 PMAI Evy
02/03/2026, 10:31 PMAI Evy
02/03/2026, 10:31 PMargs field containing the LLM-generated arguments [(2) ]()
You can also use const values for fixed inputs:
In your parameter schema, you can set "const" to hardcode a value (including dynamic variables) instead of having the LLM decide:
json
{
"type": "object",
"properties": {
"order_id": {
"type": "number",
"const": 1234
},
"last_name": {
"type": "string",
"const": "{{last_name}}"
},
"first_name": {
"type": "string",
"description": "User first name"
}
}
}
In this example:
- order_id is always 1234 (const)
- last_name uses a dynamic variable (const)
- first_name is resolved by the LLM based on the description
For query parameters, there's also a switch to toggle between description (LLM-resolved) and const value (applied directly) .AI Evy
02/03/2026, 10:31 PMAI Evy
02/03/2026, 10:31 PMpunk8357
02/03/2026, 10:33 PMAI Evy
02/03/2026, 10:33 PMAI Evy
02/03/2026, 10:33 PM[Conversation Node: Ask for preferred time]
↓
[Function Node: Check calendar availability]
↓
[Conversation Node: Handle result]
↓ (no availability found) → loops back to ask for new time
↓ (availability found) → proceed to booking
Use equation conditions based on the function result (stored as a dynamic variable) or prompt conditions to determine whether to loop back or proceed. [(2) ]()AI Evy
02/03/2026, 10:33 PMAI Evy
02/03/2026, 10:33 PMpunk8357
02/04/2026, 12:56 AMAI Evy
02/04/2026, 12:56 AMAI Evy
02/04/2026, 12:56 AMAI Evy
02/04/2026, 12:56 AMAI Evy
02/04/2026, 12:56 AMUser said yes → routes to Node A
- Prompt condition: User said no → routes to Node B
The transition happens when the user is done speaking, and the LLM evaluates which condition is met. [(2) ]() [(3) ]()
Function Nodes are specifically for executing custom functions and API calls—they don't handle conversational branching based on user responses. [(1) ]()
Quick summary:
- Conversation Node → dialogue + routing based on user responses
- Function Node → execute actions/API callsAI Evy
02/04/2026, 1:13 AMpunk8357
02/04/2026, 1:13 AMAI Evy
02/04/2026, 1:14 AMAI Evy
02/04/2026, 1:14 AMUser responds to question of their age
- User said something about booking a meeting
- User has provided their name and phone number
2. Cover all possible cases in your transition conditions to ensure smooth flow and prevent the agent from getting stuck or transitioning prematurely.
3. Use equation conditions to check if dynamic variables exist before transitioning:
{{name}} exists
{{user_email}} exists
{{user_phone}} not exists
4. Update your node instruction and global prompt to focus on the specific task. One community member had a similar issue and resolved it by changing the global prompt so the agent's mission was to "work through each node" rather than broadly "collect customer details"—and making transitions more specific. [(2) ]()
5. Add fine-tune examples if you observe incorrect transitions—you can add transition finetune examples to help the model learn when transitions should and shouldn't happen. [(1) ]()
Important: The transition happens after the user is done speaking, and the LLM evaluates which condition is met. [(3) ]() If your condition is too vague, the LLM may determine it's satisfied before you intended.AI Evy
02/04/2026, 1:14 AMpunk8357
02/04/2026, 1:15 AMAI Evy
02/04/2026, 1:15 AMpunk8357
02/04/2026, 1:15 AMAI Evy
02/04/2026, 1:16 AM{{name}} exists in the transition conditions, not in the prompt. [(1) ]()
Specifically, you select Equation as the transition condition type (not Prompt) .
Example equation conditions for checking if dynamic variables exist:
{{variable_name}} exists
{{variable_name}} does not exists
{{user_email}} exists
{{user_phone}} not exists
This returns true if the variable is defined and has a value, which is useful for ensuring information has been collected before transitioning.
Note: You can only use variables that are passed in as dynamic variables for equation conditions. If you need to use information extracted by the LLM during the call (like a name the user just provided) , you would need to use a prompt condition instead—for example: User has provided their name.AI Evy
02/04/2026, 1:16 AMAI Evy
02/04/2026, 1:16 AMpunk8357
02/04/2026, 1:22 AMAI Evy
02/04/2026, 1:22 AMAI Evy
02/04/2026, 1:22 AM{} in your debug output indicates no parameters were sent to your function. [(1) ]()
To make the agent send parameters, you need to define them in your function's parameter schema.
When you configure a custom function, you define parameters using JSON schema format. For each parameter, you provide a description that tells the LLM what information to extract from the conversation.
Example parameter schema for your use case:
json
{
"type": "object",
"required": [
"phone",
"first_name",
"last_name",
"dob"
],
"properties": {
"phone": {
"type": "string",
"description": "Patient's phone number"
},
"first_name": {
"type": "string",
"description": "Patient's first name"
},
"last_name": {
"type": "string",
"description": "Patient's last name"
},
"dob": {
"type": "string",
"description": "Patient's date of birth"
}
}
}
Key points:
- Make sure "type": "object" is at the top level of your JSON schema—this is a common mistake that causes save failures
- The LLM uses the description field to extract/generate values from the conversation [(2) ]()
- You can also use "const" for fixed values or dynamic variables like "const": "{{patient_phone}}" [(1) ]()
Also check: Before the function node is called, ensure the conversation has actually collected the required information. If the agent transitions to the function node before gathering patient details, the LLM won't have anything to extract.AI Evy
02/04/2026, 1:22 AMAI Evy
02/04/2026, 1:22 AMpunk8357
02/04/2026, 1:33 AMAI Evy
02/04/2026, 1:33 AMAI Evy
02/04/2026, 1:34 AMargs field of the request body. [(1) ]()
When Retell calls your custom function endpoint (for POST, PUT, and PATCH requests) , the request body is in JSON format and includes:
- `name`: the name of the custom function
- `call`: the call object with context about the call, including real-time transcript up to when the request is sent
- `args`: the arguments for the custom function, as a JSON object
So if your function expects phone, first_name, last_name, and dob, you would access them from args in your backend code. For example, in the request body you'd receive something like:
json
{
"name": "verifypatient",
"call": { ... },
"args": {
"phone": "555-1234",
"first_name": "John",
"last_name": "Doe",
"dob": "1990-01-15"
}
}AI Evy
02/04/2026, 1:34 AMAI Evy
02/04/2026, 1:34 AMAI Evy
02/04/2026, 1:54 AMpunk8357
02/04/2026, 1:54 AMAI Evy
02/04/2026, 1:54 AMdestination_node_id that specifies exactly where to go when that condition is met [(1) ]() [(2) ]()
- For equation conditions, they are evaluated from top to bottom, and the agent travels on the first condition that evaluates to true [(1) ]()
- The agent doesn't interpret the purpose of the destination node—it simply follows the path when the condition is satisfied
Example from the API:
json
{
"edges": [
{
"id": "edge_1",
"transition_condition": {
"type": "prompt",
"prompt": "Customer wants to book appointment"
},
"destination_node_id": "book_appointment"
}
]
}
[(2) ]()
So if you use an equation like {{user_age}} > 18, the agent doesn't need to understand why it's going to the next node—it just goes there when the equation evaluates to true. The routing is hardcoded by the destination_node_id, not decided by the LLM. [(1) ]()
Key distinction:
- **Prompt conditions**: LLM evaluates whether the condition is met based on conversation context
- **Equation conditions**: Hardcoded mathematical/logical evaluation—no LLM interpretation neededAI Evy
02/04/2026, 1:54 AMAI Evy
02/04/2026, 1:54 AMpunk8357
02/05/2026, 4:58 AMAI Evy
02/05/2026, 4:58 AMAI Evy
02/05/2026, 4:59 AMretell_llm_dynamic_variables field for outbound calls, or via the inbound webhook) . [(2) ]()
- Information the agent collects during the conversation (like a name the user just provided) is not automatically stored as a dynamic variable that equation conditions can check.
What to do instead:
1. Use prompt conditions for information gathered during the call—for example: User has provided their name and phone number [(1) ]()
2. Use equation conditions only for variables you've pre-populated before the call starts, or for system default variables like {{current_time}}, {{direction}}, {{user_number}}, etc. [(2) ]()
A community member experienced this exact issue—the equation {{status}} exists wasn't working because the variable wasn't a pre-set dynamic variable. The node was waiting for a user response before transitioning. [(3) ]()
Summary: Switch your transition conditions from equations to prompt conditions if you're checking for information the LLM collectedAI Evy
02/05/2026, 4:59 AMAI Evy
02/05/2026, 4:59 AMAI Evy
02/05/2026, 4:59 AMpunk8357
02/05/2026, 5:00 AMAI Evy
02/05/2026, 5:00 AMAI Evy
02/05/2026, 5:00 AMretell_llm_dynamic_variables field when calling the Create Phone Call API [(1) ]()
- For **inbound calls**: You supply them via the Inbound Call Webhook
The key limitation:
You can only use variables that are passed in as dynamic variables for equation conditions. If you need to use information extracted by the LLM (such as information learned during the call) , you can use prompt conditions. [(2) ]()
What this means for your use case:
If you want to check whether the agent has collected information (like a name, phone, DOB) during the conversation, you cannot use equation conditions like {{name}} exists. Instead, use prompt conditions such as:
- User has provided their name
- User has provided their phone number and date of birth
The LLM will evaluate whether that information has been gathered based on the conversation context.
Summary:
- Equation conditions → only for pre-set dynamic variables or system defaults like {{current_time}}, {{user_number}}, etc. [(1) ]()
- Prompt conditions → for information the agent collects during the call [(2) ]()AI Evy
02/05/2026, 5:00 AMAI Evy
02/05/2026, 5:00 AMpunk8357
02/05/2026, 5:02 AMAI Evy
02/05/2026, 5:02 AMAI Evy
02/05/2026, 5:02 AMUser has provided their first name, last name, date of birth, and phone number
- User responds to question of their age
- User said something about booking a meeting
2. Cover all possible cases in your transition conditions to ensure smooth flow and prevent the agent from transitioning prematurely.
3. Add transition finetune examples — if you observe the agent transitioning before collecting all info, you can add finetune examples showing the expected behavior. One community member had this exact issue where the caller provided their name upfront, causing the flow to stall. The solution was to use transition finetune examples showing that when certain info is already provided, the agent should still proceed correctly. [(2) ]()
Additionally, you can use "Extract Variables in Real Time" — this feature lets agents extract and store dynamic variables mid-conversation with reliably and accurately retrieved information. Your agents can automatically save names, emails, budgets, and preferences, then reference collected data anytime during the call. [(3) ]()
Summary approach:
- Use detailed prompt conditions like User has provided their phone number AND (first name AND last name AND date of birth)
- Add finetune examples if the agent transitions incorrectly
- Consider using real-time variable extraction to store collected infoAI Evy
02/05/2026, 5:02 AMAI Evy
02/05/2026, 5:02 AMpunk8357
02/05/2026, 5:03 AMAI Evy
02/05/2026, 5:03 AMAI Evy
02/05/2026, 5:04 AMText, Number, Enum, or Boolean
- Enum Options – Options to choose from (only when type is enum)
Variable types you can collect: [(1) ]() [(2) ]()
- **Text**: Names, addresses, feedback
- **Numbers**: Ages, quantities, prices
- **Boolean**: Yes/no decisions, preferences
- **Enum**: Predefined lists (services, products, etc.)
What this enables: [(2) ]()
- ✅ Automatically save names, emails, budgets, and preferences
- ✅ Reference collected data anytime during the call
- ✅ Pass dynamic variables to webhooks, CRMs, or integrations
- ✅ Personalize workflows in real time
This works in single, multi-prompt, and conversation flow agents.
Important notes from the community: [(3) ]() [(4) ]()
- Make sure "Wait for result" is enabled in Transition timing
- When using transitions from this node, ensure variables are referenced with double curly braces like {{variable_name}}
- Keep variable descriptions clear and concise
See the full documentation: [EAI Evy
02/05/2026, 5:04 AMAI Evy
02/05/2026, 5:04 AMpunk8357
02/05/2026, 5:05 AMAI Evy
02/05/2026, 5:05 AMAI Evy
02/05/2026, 5:05 AMAI Evy
02/05/2026, 5:05 AMAI Evy
02/05/2026, 5:05 AMpunk8357
02/05/2026, 5:06 AMAI Evy
02/05/2026, 5:06 AMAI Evy
02/05/2026, 5:07 AM{{variable_name}} syntax in the const field of your function's parameter schema. [(2) ]()
Example:
json
{
"type": "object",
"properties": {
"first_name": {
"type": "string",
"const": "{{first_name}}"
},
"last_name": {
"type": "string",
"const": "{{last_name}}"
}
}
}
2. This is more reliable than relying on the LLM to extract values at function-call time. When you use EDV nodes first, the variables are explicitly stored. Then in your function node, you reference them with const values—the LLM doesn't have to re-interpret the conversation to fill those parameters.
3. You can also set response variables from your function to store API response data for use later in the flow.
Common issue to avoid: When referencing extracted variables in function parameters, use the variable name directly like `{{variable_name}}`—not nested paths like {{extraction_node.variable_name}}. [(3) ]() [(4) ]()
Summary: EDV nodes give you explicit control over what gets captured and stored, making your function calls more predictable and reliable than having the LLM infer parameter values on the fly.AI Evy
02/05/2026, 5:07 AMAI Evy
02/05/2026, 5:07 AMpunk8357
02/05/2026, 5:26 AMAI Evy
02/05/2026, 5:26 AMAI Evy
02/05/2026, 5:26 AM"If the conversation should follow branch B1..." doesn't describe what the user actually said or what information was collected.
How to fix it: Write conditions that clearly describe what must happen in the conversation.
Examples of good prompt conditions:
- User has provided their phone number, first name, last name, and date of birth
- User responds to question of their age
- User said something about booking a meeting
Recommended approach for your case:
Change your transition condition to something like:
- User has provided the patient's phone number, first name, last name, and date of birth
Or if you want to ensure all four pieces of info are collected:
- User has answered all questions about the patient's phone, first name, last name, and date of birth
Additional tips: [(1) ]() [(2) ]()
- Make sure your prompt is concise and declarative
- Match actual language patterns the user would say
- Focus only on the content of `transition_condition.prompt`—the condition field is not used by the LLM to trigger transitions [(2) ]()
If you've observed incorrect transitions, you can also add transition finetune examples to improve behavior. [(1) ]()AI Evy
02/05/2026, 5:26 AMAI Evy
02/05/2026, 5:26 AMpunk8357
02/12/2026, 6:41 PMAI Evy
02/12/2026, 6:41 PMAI Evy
02/12/2026, 6:41 PM{{first_name}}, {{email}}, etc. to personalize messages
To send outbound SMS programmatically, use the Create Outbound SMS API: [(2) ]()
javascript
import Retell from 'retell-sdk';
const client = new Retell({
apiKey: 'YOUR_RETELL_API_KEY',
}) ;
const chatResponse = await client.chat.createSMSChat({
from_number: '+12137771234',
to_number: '+14155551234',
}) ;
console.log(chatResponse.agent_id) ;
Note: You can use your existing voice number to send SMS (local, toll-free, or branded) —no additional SMS provider setup is required. [(1) ]() However, you'll need A2P registration sorted out for SMS compliance. [(3) ]()AI Evy
02/12/2026, 6:41 PMAI Evy
02/12/2026, 6:41 PMpunk8357
02/12/2026, 6:42 PMAI Evy
02/12/2026, 6:42 PMAI Evy
02/12/2026, 6:42 PMAI Evy
02/12/2026, 6:42 PMAI Evy
02/12/2026, 6:42 PM