Install
openclaw skills install agentcallGive your agent real phone numbers for SMS, OTP verification, and voice calls via the AgentCall API.
openclaw skills install agentcallYou have access to the AgentCall API for phone numbers, SMS, voice calls, and AI voice calls. Inbound and outbound calls can both be answered or initiated by an AI voice agent.
All authenticated requests require: Authorization: Bearer <AGENTCALL_API_KEY>
The API key is available in the AGENTCALL_API_KEY environment variable.
https://api.agentcall.co
For a complete plain-text API reference: GET https://api.agentcall.co/llms.txt (no auth required).
Several tools below take real-world actions on the user's behalf. Confirm with the user before invoking them, and stay within the scope of what they explicitly asked you to do.
Billable actions (cost real money. Confirm scope first):
POST /v1/numbers/provision: recurring monthly cost ($2.00–$2.50/month depending on type). Confirm the user wants a new number; ask which type, country, and label before provisioning.POST /v1/sms/send: $0.015/message on Pro (10/month free on Free plan). Confirm the recipient number and the message body before sending.POST /v1/calls/initiate: $0.035/min on Pro. Confirm the destination number and purpose before dialing. Optional record: true adds $0.01/min on top.POST /v1/calls/ai: $0.40/min on Pro. Confirm the destination, the system prompt, and maxDurationSecs before dialing. Outbound AI calls reach a real human and accumulate cost per minute.POST /v1/numbers/:id/inbound-config with mode: "ai"). Free tier includes 5 minutes/month with no card required. Once the trial is exhausted, additional inbound AI calls hang up at the carrier with status trial_exhausted until the trial resets on the 1st of next month (UTC), OR until the user upgrades to Pro for unlimited inbound AI at $0.40/min on every incoming call. There is no pay-as-you-go overage path on Free. Confirm the user wants inbound AI enabled on this specific number, and that the system prompt accurately describes their business.record: true on AI voice paths. $0.01/min on top of the AI rate. Mention this delta when proposing recording.Irreversible actions:
DELETE /v1/numbers/:id: releases the number permanently. The same number cannot be re-provisioned. Always confirm before releasing, and warn the user that this is irreversible.POST /v1/calls/:callId/hangup: terminates an in-flight call. Usually fine but confirm if the call may still be progressing toward its goal.External-effect actions (contact real people):
firstMessage when record: true is set on AI voice paths and the message doesn't already mention recording. But you should still mention recording in firstMessage content for clarity if the user is writing one from scratch.Built-in API guardrails (don't rely on these as your only check):
setupUrl if a Pro user has no card. Surface this to the user instead of looping.plan_limit_inbound_ai_trial_exhausted with an upgradeUrl. There is no pay-as-you-go overage path on Free; the trial resets on the 1st of each month (UTC).carrier_not_supported for other countries.configure_inbound_ai and POST /v1/numbers/:id/inbound-config with mode: "ai" should follow this procedure every time:
Pre-flight checklist (require the user to confirm each before invocation):
record: true or false). Default to false. Confirm explicit opt-in if the user wants recording.notify.emailTo). Confirm the address belongs to the user and that they want post-call summaries delivered to it.maxDurationSecs). Pick the smallest value that fits the use case rather than relying on the 600-second default.Post-configuration responsibility:
get_usage or point the user at the dashboard at /billing.disable_inbound_ai (or DELETE /v1/numbers/:id/inbound-config) when the user's stated goal has been met (testing finished, campaign over, business closed for the season).disable_inbound_ai first, then investigate.If the user's request is ambiguous (e.g. "set up a phone number" with no type or country, or "send a text" with no recipient), ask one or two clarifying questions before invoking a billable tool.
Provision a number:
POST /v1/numbers/provision
Body: { "type": "local", "country": "US", "label": "my-agent" }
Types: local ($2/mo), tollfree ($2.50/mo), mobile ($2/mo). All numbers are VoIP-routed via licensed US carriers; not for consumer-platform signup verification (Stripe, WhatsApp, Google, banks).
Response: { "id": "num_xxx", "number": "+12125551234", "type": "local", ... }
List numbers:
GET /v1/numbers
Query: ?limit=20&country=US&type=local
Get number details:
GET /v1/numbers/:id
Release a number (irreversible):
DELETE /v1/numbers/:id
Rename a number or change its inbound AI voice (partial update, preserves all other inbound config):
PATCH /v1/numbers/:id
Body: { "label": "Hermes assistant" } // rename only
Body: { "voice": "marin" } // voice only (requires inbound AI already configured)
Body: { "label": "Hermes", "voice": "coral" } // both at once
Voices: alloy, ash, ballad, cedar, coral, echo, marin, sage, shimmer, verse
Response: full number object including updated `inbound` block.
Use this when the user wants to change the voice on an existing receptionist. Do NOT call POST /v1/numbers/:id/inbound-config for a voice change — that endpoint replaces the entire inbound config and would wipe the system prompt, first message, recording flag, and notify block.
Configure a phone number so incoming calls are answered autonomously by an AI voice agent. The AI follows the system prompt you set.
After every call, AgentCall summarizes the transcript with an LLM and emails a plain-English summary. Caller name (when given), phone, urgency tag, and a 1-2 sentence ask. To an address you configure on the number. Spam calls are auto-suppressed from the email. The structured call.transcript webhook event still fires in parallel for programmatic consumers.
Configure inbound AI on a number:
POST /v1/numbers/:numberId/inbound-config
Body: {
"mode": "ai",
"systemPrompt": "You are the front desk for Acme Plumbing. Greet the caller warmly, take their name and a brief description of the issue, then say someone will call back within 24 hours.",
"voice": "shimmer",
"firstMessage": "Hi, thanks for calling Acme Plumbing. How can I help?",
"maxDurationSecs": 300,
"notify": {
"emailTo": "owner@acmeplumbing.com",
"businessName": "Acme Plumbing",
"agencyName": "Acme Plumbing"
}
}
The notify block is optional. Set notify.emailTo to receive the post-call summary email; businessName is shown in the email subject; agencyName is the sign-off line. The MCP configure_inbound_ai tool also accepts notify: agents in Claude Desktop, Cursor, Windsurf, etc. can configure the email destination in the same call as the system prompt, no dashboard handoff needed.
Pre-call context webhook (optional): add a contextWebhook block to wire a live context source onto the number. When set, AgentCall POSTs to your HTTPS URL on every inbound call connect (HMAC-signed with signingSecret); your endpoint responds with {"contextBlock":"..."} and AgentCall merges that string onto the system prompt before the AI answers. Useful for injecting today's brief, current priorities, or recent email signals so the AI speaks with up-to-date data instead of a static prompt. Example:
"contextWebhook": {
"url": "https://hermes.your-domain.com/agentcall/precall",
"signingSecret": "<32+ char shared secret>",
"timeoutMs": 1200
}
Fail-open: any error in the webhook leaves the call running with the static prompt. Walkthrough at https://agentcall.co/docs/hermes.
Optional call recording (Pro plan, $0.01/min on top of the AI voice rate):
Add record: true to the body above (or flick the toggle on the dashboard's /numbers config form) to record every inbound call to this number. Recordings live in your AgentCall dashboard for 1 year and are listenable from the Logs → Calls tab or via GET /v1/calls/:callId/recording (returns a fresh short-lived signed URL). The call.recording webhook fires when each recording is ready. The same record flag is supported on outbound AI voice (POST /v1/calls/ai). When recording is on, AgentCall auto-prepends a TCPA-compliant disclosure to the spoken firstMessage if it doesn't already mention recording.
Get current inbound config:
GET /v1/numbers/:numberId/inbound-config
Disable inbound AI (calls hang up at carrier):
DELETE /v1/numbers/:numberId/inbound-config
Both endpoints are public. Call them before configuring AI voice to avoid hallucinated business details and to pick a voice that fits the use case.
List the 10 voices with samples:
GET /v1/calls/voices
Returns: { voices: [{ id, name, trait, description, bestFor, sampleUrl? }, ...], defaultVoice: "shimmer" }
The newest natural-sounding picks are marin (soft, natural) and cedar (warm, grounded). The original 8 (shimmer, sage, ash, ballad, coral, echo, verse, alloy) ship with sample MP3s; marin and cedar are live-preview only for now.
List ready-made prompt templates:
GET /v1/calls/prompt-templates
Returns 5 templates with [BRACKETED] placeholders to fill in:
- receptionist (Front Desk). Recommends shimmer voice
- lead-qualifier (Sales, BANT-style). Coral
- appointment-booker. Sage
- customer-support (FAQ Deflection). Ash
- call-screener (Anti-Spam). Verse
Each entry includes: id, title, description, recommendedVoice, maxDurationSecs, firstMessage, systemPrompt.
For a comprehensive prompt-writing guide: https://agentcall.co/docs/voice-prompts
Send SMS:
POST /v1/sms/send
Body: { "from": "num_xxx", "to": "+14155551234", "body": "Hello!" }
"from" can be a number ID or E.164 phone string
Get inbox:
GET /v1/sms/inbox/:numberId
Query: ?limit=20&otpOnly=true
Get a specific message:
GET /v1/sms/:messageId
Wait for OTP code (long-polls up to 60 seconds):
GET /v1/sms/otp/:numberId
Query: ?timeout=60000
Response: { "otp": "482913", "message": { ... } }
Start a standard outbound call:
POST /v1/calls/initiate
Body: { "from": "num_xxx", "to": "+14155551234", "record": false }
Start an outbound AI voice call (Pro plan, $0.40/min. Billable, contacts real human, confirm with user first): The AI handles the entire conversation autonomously based on your systemPrompt.
POST /v1/calls/ai
Body: {
"from": "num_xxx",
"to": "+14155551234",
"systemPrompt": "You are calling to schedule a dentist appointment for Tuesday afternoon.",
"voice": "shimmer",
"firstMessage": "Hi, I'd like to schedule an appointment please.",
"maxDurationSecs": 600,
"record": false
}
Add record: true to capture an mp3 of the call. Adds $0.01/min on top.
Voices (10 total, default: shimmer; preview the original 8 via GET /v1/calls/voices, marin and cedar are live-preview only):
List call history:
GET /v1/calls
Query: ?limit=20
Get call details:
GET /v1/calls/:callId
Get AI call transcript:
GET /v1/calls/:callId/transcript
Response: { "entries": [{ "role": "ai" | "human", "text": "...", "timestamp": "..." }], "summary": "...", "duration": 111 }
Hang up an active call:
POST /v1/calls/:callId/hangup
Important: webhooks here are for OUTBOUND event delivery, NOT inbound call routing. AgentCall POSTs to your URL when events fire (SMS received, OTP detected, call completed, recording ready, etc.). Webhooks are NOT how you make a phone number answer incoming calls. To configure how a number answers when called, use the Inbound AI Voice section above (
POST /v1/numbers/:numberId/inbound-config). Not webhooks. (If you're coming from Twilio: AgentCall replaces Twilio's inbound voice webhook URL withconfigure_inbound_ai.)
Register a webhook:
POST /v1/webhooks
Body: { "url": "https://example.com/hook", "events": ["sms.inbound", "sms.otp", "call.status"] }
Events: sms.inbound, sms.otp, call.inbound, call.ringing, call.status, call.recording, call.transcript, number.released
List webhooks:
GET /v1/webhooks
Rotate webhook secret:
POST /v1/webhooks/:id/rotate
Delete a webhook:
DELETE /v1/webhooks/:id
Get usage breakdown:
GET /v1/usage
Query: ?period=2026-04
Pricing (per use, Pro plan):
All phone numbers must be E.164: +{country code}{number}, e.g. +14155551234
POST /v1/numbers/provision with { "type": "local" }: get a numberGET /v1/calls/prompt-templates: pick a template (e.g. "receptionist")[BRACKETED] placeholders with the customer's real business detailsPOST /v1/numbers/:numberId/inbound-config with { "mode": "ai", "systemPrompt": "...", "voice": "shimmer", "firstMessage": "..." }GET /v1/calls to see incoming call history; GET /v1/calls/:callId/transcript for transcriptsPOST /v1/numbers/provision with { "type": "local" }: get a test numberGET /v1/sms/otp/:numberId?timeout=60000: wait for the verification codeDELETE /v1/numbers/:id: release the test numberPOST /v1/numbers/provision with { "type": "local" }: get a number (if you don't have one)POST /v1/calls/ai with { "from": "num_xxx", "to": "+1...", "systemPrompt": "..." }: start the callGET /v1/calls/:callId/transcript: get the full conversation transcriptsetupUrl to Stripe Checkout)upgradeUrl. Trial resets on the 1st of next month (UTC) or the user can upgrade to Pro for unlimited inbound AI.