Voice API

Place outbound phone calls from your AI agent with a single API request. Give the bot a goal, the facts it needs, and a script to follow - it handles the rest. Debt collection, appointment reminders, sales follow-ups, customer surveys - any call where you know what the bot should accomplish.

How it works

One POST request places the call. Your bot dials the number, greets the recipient, carries the conversation based on the goal and facts you provided, and ends when the objective is met.

POST /v1/voice/calls
Authorization: Bearer mbn_live_...
Content-Type: application/json
Idempotency-Key: <unique-uuid>

{
  "from": "+16473705600",
  "to": "+16475551234",
  "triggeredBy": "your-system-name",
  "task": {
    "goal":   "What the bot should accomplish",
    "script": "which-playbook-script-to-follow",
    "facts":  { "key": "value pairs the bot can reference" },
    "escalation": "When and how to escalate"
  }
}

The bot handles the conversation autonomously - verifying the recipient, delivering the message, handling objections, and closing the call. Every call is recorded, audited, and rate-limited.

Real example: debt collection call

Let's say your company Vello needs to collect $154.56 from a customer named Bobby for 1,000 SMS credits. Here's the API call:

curl -X POST "https://api.talktomyagent.io/v1/voice/calls" \
  -H "Authorization: Bearer mbn_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "from": "+16473705600",
    "to": "+16478359044",
    "targetName": "Bobby",
    "triggeredBy": "vello-billing-system",
    "maxDurationSecs": 300,
    "task": {
      "goal": "Collect $154.56 from Bobby for SMS credits; offer payment link; escalate if refused.",
      "script": "debt-collection",
      "facts": {
        "debtor_name": "Bobby",
        "amount_due": "$154.56",
        "currency": "USD",
        "due_date": "May 25, 2026",
        "purchase": "1,000 SMS credits",
        "payment_link": "https://pay.vello.io/inv/bobby-154",
        "creditor": "Vello"
      },
      "escalation": "If customer refuses to pay, use openclaw_query to email joe@vello.io with a one-line summary."
    }
  }'

What the bot does

Bobby's phone rings. When he picks up, the bot says something like:

“Hi, is this Bobby? - Hi Bobby, this is Donna calling on behalf of Vello about your recent purchase. You have an outstanding balance of $154.56 for 1,000 SMS credits, due May 25th. I can text you a payment link right now if that works?”

From there, the bot handles Bobby's response naturally:

  • Bobby agrees to pay - bot confirms and sends the payment link via SMS
  • Bobby needs more time - bot asks for a specific date and logs it
  • Bobby refuses - bot closes politely and escalates to joe@vello.io
  • ?Bobby disputes the charge - bot says someone will follow up and ends the call

The bot knows what to do because you configured a script profile in your agent's playbook - a simple markdown file on disk. See Setting up script profiles below.

The "task" object

The task object is the structured brief you hand the bot for each call. It has four fields:

goal required

One sentence describing what success looks like for this call. The bot reads this as its primary objective.

"goal": "Collect $154.56 from Bobby for SMS credits; offer payment link; escalate if refused."

facts optional

Key-value pairs the bot can reference during the call. The bot will ONLY use these facts - it won't invent data. Values can be strings, numbers, or booleans.

"facts": {
  "debtor_name": "Bobby",
  "amount_due": "$154.56",
  "due_date": "May 25, 2026",
  "payment_link": "https://pay.vello.io/inv/bobby-154"
}

Limits: up to 30 keys, string values up to 500 characters, total payload under 4 KB.

script optional

The name of a script profile in your agent's voice playbook. This tells the bot HOW to handle this type of call - the opening line, response branches, hard limits, and closing behavior.

"script": "debt-collection"

If the named script doesn't exist in your playbook, the bot falls back to general outbound guidance and a "script-not-found" warning appears in the response.

escalation optional

A plain-English rule telling the bot when and how to escalate. The bot acts on this via your agent's installed tools (email, CRM, etc.) - the platform doesn't enforce a specific escalation method.

"escalation": "If customer refuses to pay, use openclaw_query to email joe@vello.io with a summary."

You can also use the legacy purpose field (a single free-text string) instead of task for simpler calls. The two are mutually exclusive - provide one or the other, not both.

Setting up script profiles

Script profiles live in your agent's voice playbook - a markdown file on disk at protocols/dojo-voice-agent-playbook.md. Each profile is a #### heading under the ## Outbound Mode > Script profiles section.

Here's what the debt-collection profile looks like:

#### debt-collection

**Goal recap**: collect the amount due, offer the payment link.

**Expected facts**: debtor_name, amount_due, due_date,
  payment_link, creditor, purchase

**Opening** (verify identity first):
"Hi, is this {facts.debtor_name}? - Hi {facts.debtor_name},
this is {AGENT_NAME} on behalf of {facts.creditor} about your
{facts.purchase} purchase, {facts.amount_due}, that was due
{facts.due_date}."

**Branches**:
- Agrees to pay -> confirm + share {facts.payment_link} + close
- Refuses -> run openclaw_query to email the escalation contact
- Disputes -> "I'll have someone email you the details" + close
- Voicemail -> leave brief message + close
- Wrong person -> apologize + close

**Hard limits**: no discounts, no credit-reporting threats
**Duration**: under 3 minutes

That's it. Pure markdown. No code, no tools to install. Your bot reads this at call time, combines it with the facts you sent in the API request, and handles the conversation.

Want multiple call types? Stack them in the same playbook. Add #### appointment-confirmation, #### reminder, #### sales-discovery - each with its own opening, branches, and limits. The script field in the API request picks which one to use.

Getting started

1Get an API key

Go to app.talktomyagent.io → API Keys. Create a key with the voice:call scope and bind it to your voice deployment.

2Place your first call

Use your agent's phone number (from the Agent Phones page) as the from field:

curl -X POST "https://api.talktomyagent.io/v1/voice/calls" \
  -H "Authorization: Bearer mbn_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "from": "+1YOUR_AGENT_PHONE",
    "to": "+1YOUR_PHONE_NUMBER",
    "purpose": "Call to confirm that the API integration is working. Say hello, chat briefly, then say goodbye.",
    "triggeredBy": "first-test"
  }'

Your phone should ring within 2 seconds. Once confirmed, switch to the structured task format for production calls.

Response

Success (200)

{
  "data": {
    "callControlId": "v3:abcDef123...",
    "expectedDialAt": "2026-05-23T19:34:15.000Z",
    "warnings": []
  }
}

callControlId is the unique identifier for the placed call - use it to correlate with recordings and audit logs. warnings surfaces soft issues (e.g. "script-not-found" if your script name doesn't match a playbook profile).

Errors

All errors use RFC 7807 problem+json format:

StatusErrorWhat it means
400validation-failedInvalid phone number, missing fields, or task failed sanitization
400voice-self-callTarget number is the deployment's own number
403voice-country-blockedTarget country not in your outbound allowlist
404not-foundDeployment doesn't exist or your key isn't scoped to it
409voice-not-provisionedVoice deployment isn't fully set up yet
429rate-limit-exceededHit the per-target (5/hr), hourly (30/hr), or daily (100/day) limit
502dial-failedTelecom provider dial failure - retry later

What you can build

Same API, same pattern. Write a script profile for each call type, send the matching task with facts - your bot handles the rest.

Security & compliance

  • Authentication: Bearer API key with voice:call scope, bound to specific deployments.
  • Idempotency: every request requires an Idempotency-Key header to prevent duplicate calls on retries.
  • Rate limits: 5 calls/hour to the same number, 30 calls/hour, 100 calls/day per deployment.
  • Country allowlist: defaults to US only (one-party consent). Add countries via your voice portal settings.
  • Audit trail: every call writes a compliance audit row with the full task, caller ID, and outcome.
  • Prompt sanitization: all text fields are screened for prompt-injection patterns before reaching the bot.

Important: The task.goal, task.facts, and task.escalation fields become part of the bot's instructions. Never pass through untrusted end-user input in these fields - always validate or author them server-side.

Full API reference

The complete OpenAPI specification with all parameters, schemas, and error codes is available as interactive documentation: