Callable docs

Everything you need to build, test, and run AI voice agents on Callable. Short and direct — no filler.

Welcome

Callable lets you build AI voice agents — virtual receptionists that book appointments, take orders, answer questions, and route calls. The agent has three parts: ears (speech-to-text), a brain (an LLM that decides what to say), and a mouth (text-to-speech). You configure all three in the agent builder.

The fastest way to learn: create your first agent from a template and click through it. The rest of these docs explain each piece.

Build your first agent

  1. Go to Agents → New agent.
  2. Pick a starting template (clinic, restaurant, hotel, etc.).
  3. Give it a name and a business name.
  4. Customize the prompt, voice, FAQs, and knowledge.
  5. Try it live in the test panel on the right.
  6. Click Save & go live.

You can also chat with the Co-pilot at the top of the sidebar — it walks you through anything.

Writing a good prompt

The agent's prompt is its core instructions. A good prompt says:

  • Who the agent is (role, business)
  • How it should sound (warm, professional, concise)
  • What it must always do (confirm the caller's name and number before booking)
  • What it must never do (give medical/legal advice, invent prices)
You are the friendly front-desk receptionist for Bella's Dental.
Always greet warmly and confirm the caller's name and phone number
before booking. Never give medical advice — if asked, offer to take
a message for the dentist.

Voice & language

In the agent builder's Voice section, browse and sample real Cartesia voices. Click ▶ to hear each one — pick whichever fits your business. Then set your primary language (40+ supported). The agent automatically replies in the language the caller uses.

Knowledge & FAQs

Three places to teach your agent things:

  • Services — short list of what you offer.
  • Questions & answers — known questions with exact answers.
  • Knowledge base — free text, or fetch your website (Business plan).

All of this is included in the prompt the AI sees on every reply, so it answers based on your real info — not made-up facts.

Tools (function calling)

Tools give your agent abilities. When a caller says “book me an appointment”, the agent can invoke a tool you've defined — like an HTTP call to your booking API, a call transfer, a text message, or ending the call.

Build tools in Tools, then attach them to an agent in the agent builder's Tools section. The AI decides when to call them. API tools make real HTTP requests; built-in actions (transfer, end call, etc.) run when phone calls go live.

Agent Teams — multi-agent hand-off

An agent team is a group of agents that hand off to each other. Example: a Front Desk answers calls, hands billing questions to a Billing agent, and emergencies to on-call staff. Define members in Agent Teams and mark which agent answers first. (Business plan.)

Evals — testing scenarios

Before going live, run a few test scenarios against your agent in Evals. Each scenario is “caller says X” plus an optional expected keyword. Click Run all tests and you see exactly what your agent replies — with PASS/FAIL when the expected keyword appears.

Integrations (bring your own keys)

Connect your own accounts in Integrations — Cal.com, Calendly, HubSpot, Slack, Discord, Zapier, Make, n8n, Twilio, ElevenLabs, Airtable, Notion, or a custom webhook. Each one asks for your API key or webhook URL. Callable never uses our own credentials on your behalf — your data, your keys.

Plans & limits

Three plans, all enforced in code:

  • Pay as you go ($20/mo) — 1 agent, core builder.
  • Pro ($50/mo) — 5 agents, Tools, Evals, Integrations.
  • Business ($80/mo) — Unlimited agents, Agent Teams, website-URL knowledge import.

Try to save more agents than your plan allows and you'll see an upgrade prompt. Switch plans any time in Settings.

Live phone calls (coming)

Today you can build agents and talk to them in the browser (text or voice). To make them answer a real phone number, Callable needs a telephony provider wired up — Twilio, Telnyx, Bandwidth, SignalWire, or Plivo all work. Add the provider's keys to .env.local, point its inbound webhook at /api/twilio/voice, and your agent answers real calls. Pro and Business plans include live phone at launch.

SDK & API reference

Callable exposes the same /api/chat endpoint your test panel uses. Hit it from any language. Add the x-byo-openai-key header (or any other BYOK header from Integrations) and your call gets billed to your own key.

REST endpoint

POST https://your-domain.com/api/chat

Body: { agent: AgentConfig, messages: Msg[], tools?: ToolDef[] }
Response: { reply: string, usage?: {...}, toolsUsed?: string[] }

cURL

curl -X POST https://your-domain.com/api/chat \
  -H 'content-type: application/json' \
  -H 'x-byo-openai-key: sk-...' \
  -d '{
    "agent": {
      "businessName": "Bella'"'"'s Dental",
      "personality": "friendly",
      "modelSettings": { "provider": "openai", "model": "gpt-4o-mini" }
    },
    "messages": [
      { "role": "user", "content": "Can I book a cleaning Tuesday at 3pm?" }
    ]
  }'

JavaScript / Node

async function ask(message) {
  const res = await fetch("https://your-domain.com/api/chat", {
    method: "POST",
    headers: {
      "content-type": "application/json",
      // optional — use your own OpenAI key (BYOK)
      "x-byo-openai-key": process.env.OPENAI_API_KEY,
    },
    body: JSON.stringify({
      agent: {
        businessName: "Bella's Dental",
        personality: "professional",
        modelSettings: { provider: "openai", model: "gpt-4o-mini" },
      },
      messages: [{ role: "user", content: message }],
    }),
  });
  const data = await res.json();
  return data.reply;
}

console.log(await ask("Are you open today?"));

Python

import os, requests

def ask(message: str) -> str:
    res = requests.post(
        "https://your-domain.com/api/chat",
        headers={
            "content-type": "application/json",
            # optional BYOK
            "x-byo-openai-key": os.environ["OPENAI_API_KEY"],
        },
        json={
            "agent": {
                "businessName": "Bella's Dental",
                "personality": "concise",
                "modelSettings": {
                    "provider": "openai",
                    "model": "gpt-4o-mini",
                },
            },
            "messages": [{"role": "user", "content": message}],
        },
        timeout=30,
    )
    res.raise_for_status()
    return res.json()["reply"]

print(ask("What time do you close?"))

With tools (function calling)

const tools = [
  {
    id: "book",
    name: "book_appointment",
    type: "api",
    description: "Books a dental appointment for a patient",
    url: "https://your-app.com/api/book", // real URL Callable will POST to
    method: "POST",
    parameters: [
      { name: "patient_name", type: "string", required: true },
      { name: "date",         type: "string", required: true }, // YYYY-MM-DD
      { name: "time",         type: "string", required: true }, // HH:MM
    ],
  },
];

const res = await fetch("https://your-domain.com/api/chat", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ agent, messages, tools }),
});
const { reply, toolsUsed } = await res.json();
// → reply quotes the booking; toolsUsed includes "book_appointment"

BYOK headers

Send any of these when you have the user's key from Integrations:

  • x-byo-openai-key
  • x-byo-anthropic-key
  • x-byo-cartesia-key — for /api/speak + /api/voices
  • x-byo-deepgram-key — for /api/transcribe

Embed the chat widget

Drop the chat widget on any website. Replace AGENT_ID with your agent's id from the dashboard URL.

Inline iframe

<iframe
  src="https://your-domain.com/chat/AGENT_ID"
  style="border:0;width:380px;height:560px"
  allow="microphone"
></iframe>

Floating bubble (script tag)

<script
  src="https://your-domain.com/widget.js"
  data-agent-id="AGENT_ID"
  data-position="bottom-right"
  async
></script>

React component

import { CallableChat } from "@callable/react"; // future SDK

export default function Support() {
  return (
    <CallableChat
      agentId="AGENT_ID"
      position="bottom-right"
      onMessage={(m) => console.log("user said:", m)}
    />
  );
}

Webhooks

When a real call ends or an appointment is booked, Callable POSTs a signed JSON payload to the URL you set per-agent in the agent's Settings → Webhook. Verify the signature header to make sure it's really from us.

Event payload

POST https://yourapp.com/webhooks/callable
content-type: application/json
x-callable-signature: t=1717280000,v1=ab12...

{
  "event": "call.ended",
  "agentId": "ag_123",
  "callId": "call_abc",
  "from": "+15555550100",
  "to":   "+15555550199",
  "durationSec": 142,
  "outcome": "booked",
  "transcript": [
    { "role": "agent",  "content": "Bella's Dental, how can I help?" },
    { "role": "caller", "content": "I'd like to book Tuesday at 3." }
  ],
  "summary": "Caller booked a cleaning for Tuesday 3pm.",
  "tool_calls": [{ "name": "book_appointment", "args": { "date": "2026-06-10" } }]
}

Signature verification (Node)

import crypto from "node:crypto";

export function isFromCallable(req, secret) {
  const header = req.headers["x-callable-signature"] || "";
  const [tsPart, sigPart] = header.split(",");
  const t = tsPart?.split("=")[1];
  const v1 = sigPart?.split("=")[1];
  if (!t || !v1) return false;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(t + "." + req.rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Event types

  • call.started — caller connected
  • call.ended — final transcript + outcome
  • tool.invoked — agent called one of your tools
  • chat.message — visitor message on the embed widget
  • campaign.contact.called — outbound campaign progressed

FAQ

Does the agent learn from each call?

No. The agent has no memory between calls. On every reply, we include all your info (prompt, FAQs, knowledge) so it answers based on what you've taught it — fresh every time.

Can I use my own LLM?

Today the platform uses OpenAI (or Anthropic as a backup) on the server. BYO-LLM via the Integrations page is on the roadmap.

Is it HIPAA-compliant?

Not yet. HIPAA requires a BAA with every sub-processor (LLM, speech, telephony) and audit-grade infrastructure. We'll roll this out on Business when live phone calls launch.

Where's my data stored?

Agents are stored in Supabase (your project, your database). Integration credentials sit in your Supabase user metadata. Browser-only data (Co-pilot threads, drafts) lives in localStorage on this device.

Couldn't find what you need? Ask the Co-pilot — it can usually point you to the right page.