API · v1

The Call0 API.

Retrieve calls, manage agents, receive results via webhook, and control enabled outbound workflows through a focused REST API.

Introduction

All endpoints use the base URL https://www.call0.ai/api/v1. Requests and responses are JSON (Content-Type: application/json). Every resource is limited to the account associated with your API key.

Authentication

Create API keys in the dashboard under Developer. Keys begin with ck_live_, are shown once, and use either the read or write scope.

curl https://www.call0.ai/api/v1/calls \
  -H "Authorization: Bearer ck_live_yourKey"

An invalid key returns 401; an insufficient scope returns 403.

List calls

GET/v1/calls

Lists calls for your account, newest first. Scope: read.

FieldTypeDescription
limitintegerItems per page, max. 100 (default 20).
offsetintegerPagination offset (default 0).
agent_idstringOptional: only calls for this agent.
curl "https://www.call0.ai/api/v1/calls?limit=2" \
  -H "Authorization: Bearer ck_live_…"

Response · 200

{
  "calls": [{
    "id": "3af91e9e-…",
    "agent_id": "23061e5a-…",
    "direction": "inbound",
    "status": "completed",
    "duration_seconds": 216,
    "summary": "Table reservation for four people on Friday at 7 PM.",
    "callback_requested": false
  }],
  "total": 1,
  "limit": 2,
  "offset": 0
}

Retrieve a call

GET/v1/calls/{id}

Returns one call with its complete transcript. Scope: read. A missing call or a call owned by another account returns 404.

curl https://www.call0.ai/api/v1/calls/3af91e9e-… \
  -H "Authorization: Bearer ck_live_…"

Start a call (outbound)

POST/v1/calls/outbound

Outbound calling requires an outbound agent and an enabled project dialer. A disabled dialer returns 409 outbound_disabled.

Starts an outgoing call. Scope: write. The agent_id may identify either the outbound agent or its inbound parent.

FieldTypeDescription
agent_idstringRequired. Outbound agent or associated inbound agent ID.
tostringRequired. Destination number in E.164 format.
modestringOptional. Demo mode "1", "2", or "3" for this call only.
variablesobjectOptional conversation variables; values may contain up to 200 characters.
curl -X POST https://www.call0.ai/api/v1/calls/outbound \
  -H "Authorization: Bearer ck_live_…" \
  -H "Content-Type: application/json" \
  -d '{"agent_id":"23061e5a-…","to":"+14155550120","mode":"2"}'

Retrieve progress through GET /v1/calls/{call_id} or receive the result via webhook. A missing caller ID returns 422.

Agents

GET/v1/agents

Lists account agents with their ID, name, role, language, and status.

POST/v1/agents

FieldTypeDescription
namestringDisplay name or company name used in the greeting.
system_promptstringAgent behavior and instructions.
greetingstringGreeting or outbound opening line.
languagestringLanguage code such as de-DE, en-US, or fr-FR.
voice_idstringVoice selected from the dashboard voice library.

Webhooks

Add webhook endpoints in the dashboard under Integrations → Create webhook. After each completed conversation, Call0 sends a call.completed POST request to your URL. You can also subscribe to call.missed, call.failed, handoff.requested, handoff.connected, intake.captured and booking.created. The Docs button in the webhook dialog shows every payload, the retry schedule and the pause rules.

{
  "event": "call.completed",
  "call": {
    "id": "3af91e9e-…",
    "status": "completed",
    "duration_seconds": 216,
    "summary": "…",
    "transcript": [ … ]
  }
}

Verify X-Call0-Signature as an HMAC-SHA256 of timestamp.body using your webhook secret. The timestamp is provided in X-Call0-Timestamp. Return a 2xx status and reject stale timestamps to prevent replay attacks.

Live chat (chatbot handoff)

When a chatbot visitor asks for a person, Call0 sends the chat to your system (webhook). Your team answers through the Live Chat API and the reply appears in the chat window right away. While a team member holds the chat, the chatbot stays silent.

Set up in Chatbot → Behaviour → When a person should help → Livechat per Webhook: your endpoint, the signing secret and an API key with the scope livechat:write. That key only works for the live chat of this one chatbot; other keys are refused here.

Endpoints

Base URL https://www.call0.ai/api/v1/livechat, header Authorization: Bearer ck_live_….

MethodPathEffect
POST/conversations/{id}/messagesSend a team member reply to the visitor (takes over the chat if needed)
POST/conversations/{id}/takeoverTake over: the chatbot stops answering
POST/conversations/{id}/releaseHand back to the chatbot
POST/conversations/{id}/closeClose the conversation
GET/conversations/{id}Status and recent messages (?limit=50, max 200)
curl -X POST https://www.call0.ai/api/v1/livechat/conversations/6f1c2a9e-3b7d-4c55-9a1e-2d8f0b4c7e11/messages \
  -H "Authorization: Bearer ck_live_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: reply-4711" \
  -d '{
    "text": "Hallo, hier ist Anna vom Support. Wie kann ich helfen?",
    "author": { "name": "Anna", "avatar_url": "https://deine-firma.de/team/anna.png" }
  }'
FieldTypeDescription
textstringRequired, 1–4000 characters. Plain text; https:// links become clickable.
author.namestring?Team member name, up to 80 characters.
author.avatar_urlstring?Team member picture, https only.
idempotency_keystring?Or header Idempotency-Key. Same key → no duplicate message.

A message takes over the chat automatically. Responses: 201 (new) or 200 (repeat with the same Idempotency-Key). If a team member took the chat in the Call0 inbox, you get 409.

Events to your system

EventWhenContents
handoff.requestedVisitor asks for a personConversation, visitor, summary, transcript, links
message.createdNew visitor message while a person is in chargeConversation, message, links
conversation.closedConversation closed (API or inbox)closed_by, closed_at
{
  "id": "chatbot-handoff:6f1c2a9e-…:webhook:1761148800000",
  "event": "handoff.requested",
  "created_at": "2026-10-22T16:00:00.000Z",
  "data": {
    "conversation": {
      "id": "6f1c2a9e-3b7d-4c55-9a1e-2d8f0b4c7e11",
      "chatbot_id": "23061e5a-8c4f-4b2e-9d61-7a0e5f3c9b28",
      "status": "waiting",
      "created_at": "2026-10-22T15:58:12.000Z"
    },
    "visitor": {
      "email": null,
      "locale": "de",
      "page_url": "https://deine-firma.de/preise"
    },
    "summary": "Der Besucher fragt nach einem Angebot für 20 Nutzer.",
    "transcript": [
      {
        "id": "…",
        "role": "visitor",
        "text": "Was kostet das für 20 Nutzer?",
        "author": null,
        "created_at": "2026-10-22T15:58:12.000Z"
      },
      {
        "id": "…",
        "role": "bot",
        "text": "Gern verbinde ich dich mit dem Team.",
        "author": null,
        "created_at": "2026-10-22T15:58:14.000Z"
      }
    ],
    "links": {
      "dashboard": "https://www.call0.ai/dashboard/chatbot/inbox?agent=…&conversation=…",
      "api": "https://www.call0.ai/api/v1/livechat/conversations/6f1c2a9e-3b7d-4c55-9a1e-2d8f0b4c7e11"
    }
  }
}

Every delivery carries X-Call0-Event, X-Call0-Event-Id (same on retries), X-Call0-Timestamp and X-Call0-Signature = sha256=HMAC(secret, timestamp + "." + body). Answer with 2xx. Otherwise we retry up to 5 times with growing delays (1, 2, 4, 8 min). Targets must be publicly reachable over HTTPS.

import crypto from 'node:crypto'

// rawBody: der unveränderte Text der Anfrage
function verify(headers, rawBody, secret) {
  const ts = headers['x-call0-timestamp']
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(ts + '.' + rawBody)
    .digest('hex')
  const given = Buffer.from(headers['x-call0-signature'] || '')
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300
  return fresh && given.length === expected.length &&
    crypto.timingSafeEqual(given, Buffer.from(expected))
}

Limits

LimitValueResponse
Requests per key120 / min429 + Retry-After
Messages per conversation30 / min429 + Retry-After
Request size16 KB413
Foreign or unknown conversation—404
Chatbot is mid-answer—409 bot_busy + Retry-After: 2

Errors

FieldTypeDescription
400invalid_requestA required field is missing or malformed.
401unauthorizedThe API key is missing or invalid.
403insufficient_scopeThe key does not have the required scope.
404not_foundThe resource does not exist or belongs to another account.
422unprocessableThe request is valid but cannot be completed.
5xxserver_errorUnexpected error; retry with backoff.

Errors use { "error": "…" } with the corresponding HTTP status. Questions? Contact us.