Custom functions allow you to extend your agent’s capabilities by integrating external APIs, providing additional knowledge, or implementing custom logic.

Custom Functions Overview

You can create custom functions that will be called by the LLM when needed. When called, Retell sends a POST request to your specified URL with the function name and parameters.

1

Add custom function in dashboard

Click ”+ Add” in the tools section and select “Custom Function” from the dropdown menu.

2

Configure function details

Add a name and description for the custom function. The name should be unique and separated with underscore.

For example:

  • Name: get_weather
  • Description: Get the weather for a city
3

Add endpoint URL

Add the URL where Retell will send the POST request to execute your custom function.

4

Define parameters

Define the parameters for the custom function using JSON schema format. For guidance, refer to:

Example parameter schema:

{
  "type": "object",
  "properties": {
    "city": {
      "type": "string",
      "description": "The city of the weather"
    }
  },
  "required": [
    "city"
  ]
}
5

Configure speech behavior

Set up how the agent should handle speech during and after function execution:

  • Speak during execution: Enable if the agent should speak while the function runs
    • Enable for user-facing actions (e.g., getting weather information)
    • Disable for background tasks (e.g., attaching notes to call)
  • Speak after execution: Enable if the agent should provide feedback after the function completes

Troubleshooting

If you failed to save the custom function, it is likely because the parameters are not valid.

One common mistake is not adding "type": "object", to the top level of the JSON schema. We recommend clicking one of the examples and update accordingly.

Verifying Request is from Retell

To verify that the request is coming from Retell, you can check the X-Retell-Signature header.

The value is a encrypted request body using your secret key.

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;
  }
  const content = req.body;
  if (content.args.city === "New York") {
    return res.json("25f and sunny");
  } else {
    return res.json("20f and cloudy");
  }
});
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:
            print(
                "Received Unauthorized",
                post_data["event"],
                post_data["data"]["call_id"],
            )
            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"}
        )
You can also secure your server from public network by only allowlisting Retell IP addresses: 100.20.5.228