anicall.io API v2 and MCP server
The anicall.io REST API v2 at https://api.anicall.io/api/v2 controls agents, knowledge base, calls and dial jobs; signed webhooks report events, and the MCP server at https://api.anicall.io/mcp makes everything usable for AI agents such as Claude.
Last updated: November 2026
At a glance
- Base URL
- https://api.anicall.io/api/v2
- OpenAPI spec
- https://api.anicall.io/api/v2/openapi.json
- MCP server
- https://api.anicall.io/mcp
- Authentication
- Authorization: Bearer anc_live_…
Authentication
Every request to API v2 and the MCP server carries a key in the header Authorization: Bearer anc_live_….
Create keys in the dashboard under Settings → Integrations. anicall only stores a SHA-256 hash; you see the plain key once when you create it. Field names are camelCase, errors are returned as JSON {"error": "…", "message": "…"}.
curl https://api.anicall.io/api/v2/agents \
-H "Authorization: Bearer anc_live_…"Scopes
Every key only gets the scopes you grant; approving dial jobs (dial_jobs:approve) is a separate scope.
| Scope | Meaning |
|---|---|
agents:read | Read agents and their configuration |
agents:write | Configure agents (knowledge boundary, calendar, active status) |
knowledge:read | Read knowledge sources, knowledge gaps and knowledge search |
knowledge:write | Create knowledge sources, approve answers |
calls:read | Read calls, transcripts and outcomes |
calls:write | Start single outbound calls |
dial_jobs:write | Create and pause dial jobs |
dial_jobs:approve | Approve dial jobs (the human in the approval gate) |
phone_numbers:read | Read phone numbers |
phone_numbers:write | Assign phone numbers to agents |
calendars:read | Read calendar connections |
calendars:write | Connect calendars (Calendly) |
stats:read | Read stats |
webhooks:manage | Manage webhook subscriptions |
Endpoints
API v2 has endpoints for account, agents, knowledge base, knowledge gaps, phone numbers, calendars, calls, dial jobs, stats and webhooks.
| Method | Path | Scope | Meaning |
|---|---|---|---|
GET | /api/v2/me | agents:read | Account, plan, available scopes and event types |
GET | /api/v2/agents | agents:read | List agents |
GET | /api/v2/agents/{agentId} | agents:read | Get an agent |
PATCH | /api/v2/agents/{agentId} | agents:write | Configure an agent: knowledge boundary, calendar, active status |
GET | /api/v2/agents/{agentId}/knowledge | knowledge:read | An agent's knowledge sources |
POST | /api/v2/agents/{agentId}/knowledge | knowledge:write | Add a knowledge source (e.g. website) |
POST | /api/v2/agents/{agentId}/knowledge/search | knowledge:read | Search the knowledge base |
GET | /api/v2/agents/{agentId}/knowledge-gaps | knowledge:read | Open knowledge gaps |
POST | /api/v2/agents/{agentId}/knowledge-gaps/{gapId}/answer | knowledge:write | Answer a knowledge gap (goes into the answer catalog) |
POST | /api/v2/agents/{agentId}/knowledge-gaps/{gapId}/dismiss | knowledge:write | Dismiss a knowledge gap |
POST | /api/v2/agents/{agentId}/answers | knowledge:write | Add an answer directly to the answer catalog |
GET | /api/v2/phone-numbers | phone_numbers:read | List phone numbers |
PATCH | /api/v2/phone-numbers/{numberId} | phone_numbers:write | Assign a phone number to an agent |
GET | /api/v2/calendars | calendars:read | List calendar connections |
POST | /api/v2/calendars/calendly | calendars:write | Connect Calendly |
GET | /api/v2/calls | calls:read | Calls with outcome and review |
GET | /api/v2/calls/{callId} | calls:read | A call with transcript and summary |
POST | /api/v2/calls | calls:write | Start a single call (contact basis required) |
POST | /api/v2/dial-jobs | dial_jobs:write | Create a dial job (waits for approval) |
GET | /api/v2/dial-jobs/{jobId} | dial_jobs:write | Status of a dial job |
POST | /api/v2/dial-jobs/{jobId}/approve | dial_jobs:approve | Approve a dial job |
POST | /api/v2/dial-jobs/{jobId}/pause | dial_jobs:write | Pause a dial job |
GET | /api/v2/stats | stats:read | Stats: calls, minutes, outcomes, traffic light |
GET | /api/v2/webhooks | webhooks:manage | List webhook subscriptions |
POST | /api/v2/webhooks | webhooks:manage | Create a webhook subscription |
DELETE | /api/v2/webhooks/{webhookId} | webhooks:manage | Delete a webhook subscription |
POST | /api/v2/webhooks/{webhookId}/test | webhooks:manage | Send a test event |
Webhooks and signature
anicall signs every webhook delivery with HMAC-SHA256 over the timestamp and the raw request body.
X-Anicall-Signature: t=<unix ts>,v1=<hex HMAC-SHA256(secret, "<ts>.<body>")>Every delivery carries the headers X-Anicall-Event, X-Anicall-Delivery and X-Anicall-Signature. Verify the signature against the raw body and reject timestamps older than 5 minutes.
If a delivery fails, anicall retries after 1, 5 and 30 minutes and after 2 and 6 hours. POST /webhooks/{id}/test sends a test event.
| Event | Meaning |
|---|---|
call.started | A call has started (inbound or outbound). |
call.completed | A call has ended; transcript, summary and outcome are available. |
call.reviewed | The knowledge boundary review is done (traffic light ok/warn/fail). |
appointment.booked | The agent booked an appointment. |
callback.requested | The caller wants a callback from a human. |
knowledge.gap | A factual question could not be answered from the knowledge base. |
lead.updated | A lead has a new status or outcome. |
lead.dnc | A contact objected and is now blocked. |
dial_job.approval_required | A dial job is waiting for human approval. |
dial_job.completed | A dial job has been fully processed. |
import crypto from 'node:crypto'
// header = X-Anicall-Signature, rawBody = unveränderter Request-Body (String)
export function verifyAnicallSignature(secret, rawBody, header, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
const t = Number(parts.t)
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(parts.v1 ?? '')
return a.length === b.length && crypto.timingSafeEqual(a, b)
}MCP server for AI agents
The anicall MCP server speaks Streamable HTTP (stateless) at POST https://api.anicall.io/mcp and uses the same key and scopes as API v2.
Set up in Claude Code
Add the server with your key as a header. Other MCP clients that support Streamable HTTP with an Authorization header are set up the same way.
claude mcp add --transport http anicall https://api.anicall.io/mcp \
--header "Authorization: Bearer anc_live_…"Tools that trigger real calls are marked as destructive. Dial jobs only start after a human runs approve_dial_job.
Tools
| Tool | Meaning |
|---|---|
list_agents | List agents |
get_agent | An agent's configuration |
set_agent_strictness | Set an agent's knowledge boundary |
search_knowledge | Search the knowledge base |
add_knowledge_source | Add a knowledge source |
list_knowledge_gaps | List knowledge gaps |
answer_knowledge_gap | Answer a knowledge gap |
list_calls | Calls with outcome and traffic light |
get_call | A call with transcript and review |
start_call | Start a single call (destructive) |
create_dial_job | Create a dial job (destructive) |
approve_dial_job | Approve a dial job (destructive) |
get_dial_job | Status of a dial job |
get_stats | Stats |
Frequently asked questions
Where can I find the OpenAPI spec?
At https://api.anicall.io/api/v2/openapi.json. It contains all API v2 endpoints and works with code generators and AI agents.
Can an AI agent start calls on its own via MCP?
Single calls only with the calls:write scope and a contact basis. Call lists are created as dial jobs; they only start once a human approves them with approve_dial_job or in the dashboard.
How do I verify that a webhook really comes from anicall?
Compute HMAC-SHA256 with your webhook secret over "<t>.<raw body>" and compare the result in constant time with v1 from the X-Anicall-Signature header. Reject timestamps older than 5 minutes.
Create your first API key
In the dashboard under Settings → Integrations – with exactly the scopes your integration needs.
