Install
openclaw skills install clawcallMake real AI-powered phone calls. Use when the user wants to call someone, phone a business, follow up by phone, confirm or reschedule or cancel an appointme...
openclaw skills install clawcallYou can make real phone calls on behalf of the user. An AI agent dials the number, has the conversation, and brings back a full transcript. An API key is provisioned automatically on the first call — no manual setup required.
Base URL: https://api.clawcall.dev
+1XXXXXXXXXX).If calling a business outside likely hours (before 8 AM, after 6 PM, weekends), mention it: "It's 9 PM — the office is probably closed. Want me to try anyway, or call tomorrow morning?"
The task is the complete briefing the AI agent reads before picking up the phone. The agent knows only what's in the task. If something isn't there, it can't answer when asked.
Write the task as a clear paragraph covering what the agent should do, what it needs to know, and what to do if things don't go as planned. The task can also set boundaries — what the agent should not agree to, commit to, or share.
Strong task:
Call Dr. Rivera's office. Confirm Jordan Lee's appointment for Tuesday March 30 at 2:30 PM. If they need to reschedule, Wednesday or Thursday afternoon works. If the office is closed or no one answers, hang up.
Weak task:
Check on my appointment.
The weak version leaves the agent unable to answer "whose appointment?", "which date?", or "what should we do about it?" It will get stuck on the first follow-up question.
Optional, but make calls noticeably better:
jessica (default, female), sarah (female), chris (male), eric (male).POST /call
Content-Type: application/json
X-Api-Key: clawcall_sk_...
{
"to": "+15551234567",
"task": "Call Dr. Rivera's office. Confirm Jordan Lee's appointment for Tuesday March 30 at 2:30 PM. If they need to reschedule, Wednesday or Thursday afternoon works. If no one answers, hang up.",
"personality": "Alex, a friendly and professional assistant calling on behalf of Jordan Lee",
"greeting": "Hi, this is Alex calling on behalf of Jordan Lee regarding an upcoming appointment.",
"voice": "jessica",
"bridge_number": "+15559876543"
}
Only to and task are required. Add personality and greeting for better calls. Include bridge_number only for live handoff (see Live Handoff).
Response (201):
{
"call_id": "ba645d75-...",
"status": "queued",
"api_key": "clawcall_sk_..."
}
Every response includes an api_key field. Send it back as X-Api-Key on every subsequent request. The API key is managed automatically. You don't need to surface it in normal conversation, but it belongs to the user — share it if they ask.
Persist the key across conversations. The API key is a low-privilege session identifier (not a password or secret) — it tracks usage quota and cannot access other users' data. On first receipt, save it to ~/.config/clawcall/key.json:
{ "api_key": "clawcall_sk_..." }
If your host environment provides a secure secret store, prefer that over the file. Otherwise, the file path above is acceptable given the key's limited scope.
At the start of any new conversation involving phone calls, check for this file (or your secure store) first. If the key exists, use it — don't wait for a new one to be issued.
Poll for status every 3 seconds:
GET /call/{call_id}
X-Api-Key: clawcall_sk_...
Status progression: queued → ringing → in_progress → completed or failed
Calls can take several minutes — hold times, phone trees, long conversations. Don't give up. Keep polling until completed or failed.
Lead with the outcome. The user asked you to do something — tell them whether it got done. Include which number you called.
Then:
Response shape:
{
"call_id": "ba645d75-...",
"status": "completed",
"to": "+15551234567",
"transcript": [
{ "role": "assistant", "text": "Hi, this is Alex calling on behalf of Jordan Lee..." },
{ "role": "user", "text": "Sure, I can help. What's the date of birth on file?" },
{ "role": "assistant", "text": "I don't have that information available right now. I'll call back shortly with it." }
],
"recordingUrl": "https://...",
"api_key": "clawcall_sk_...",
"_meta": { "balance_seconds": 847 }
}
Sometimes the call completes but the transcript shows the agent hit a wall — the other person asked for information the agent didn't have, or the conversation went somewhere the task didn't cover.
When this happens:
{
"to": "+15551234567",
"task": "You're calling Dr. Rivera's office back. You called a few minutes ago about Jordan Lee's appointment but didn't have the date of birth. It's 03/15/1990. Confirm the appointment for Tuesday March 30 at 2:30 PM. Here's the transcript from the previous call for context:\n\n[previous transcript]",
"personality": "Alex, Jordan Lee's assistant",
"greeting": "Hi, this is Alex again — I just called about Jordan Lee's appointment and I have that date of birth now."
}
Including the previous transcript in the task lets the phone agent pick up naturally where it left off, as if it's the same person calling back.
| failReason | Tell the user | Next step |
|---|---|---|
no_answer | "No one picked up." | Offer to try again. Ask if there's a better time. |
busy | "The line was busy." | Offer to retry in a moment. |
call_rejected | "The call was declined." | They may screen unknown numbers. Suggest the user call directly, or try bridge mode. |
invalid_number | "That number doesn't seem to be valid." | Ask to double-check. Don't retry. |
unreachable | "That number appears to be out of service." | Ask to verify the number. Don't retry. |
dial_failed | — | Retry once silently. If it fails again, tell the user. |
network_error | — | Retry once silently. If it fails again, tell the user. |
quota_exceeded, 429){
"error": {
"code": "quota_exceeded",
"action": {
"url": "https://clawcall.dev/sign-up?token=clawcall_sk_...",
"sign_in_url": "https://clawcall.dev/sign-in?token=clawcall_sk_..."
}
}
}
Ask the user: "Do you already have a ClawCall account?"
action.url (sign-up link).action.sign_in_url (sign-in link).After they sign up or sign in, the same API key works. Retry the call.
balance_depleted, 429)Send the user action.url — it's a direct purchase link.
number_pool_exhausted, 503)Wait 15 seconds and retry automatically. Temporary congestion.
| Code | What to do |
|---|---|
invalid_phone (400) | Must be US/Canada +1. Ask user to correct it. |
missing_fields (400) | to and task are both required. |
dial_failed (502) | Retry after a few seconds. |
When the user wants the AI to handle the tedious part — phone trees, hold music, the front desk — and then be connected in to speak directly.
Don't suggest it for simple tasks the AI can fully handle.
bridge_number in the request.The transcript covers everything up to the handoff. After that, the conversation is private.
{
"to": "+15551234567",
"task": "Call Dr. Rivera's office. Navigate the phone menu and tell the receptionist you need to reschedule Jordan's appointment. Once you're speaking with someone who can help, connect me.",
"bridge_number": "+15559876543",
"personality": "Alex, Jordan's assistant"
}
New users get 20 free minutes with no sign-up.
Balance is returned in _meta.balance_seconds on poll responses and in headers on every response: X-ClawCall-Balance-Seconds, X-ClawCall-Balance-Minutes.
When balance drops below 120 seconds, mention it: "By the way, you're running low on call minutes."
To check explicitly: GET /balance with X-Api-Key header.
Don't check balance before every call. Just call. Handle errors if they come.
X-Api-Key. Save it to ~/.config/clawcall/key.json (or your host's secure store) on first receipt and load it at the start of new conversations. Share it if the user asks.action.url verbatim on quota/balance errors. It's a personalized link — don't modify or paraphrase it.+1XXXXXXXXXX.dial_failed, network_error, pool_exhausted). Ask the user before retrying no_answer, busy, or call_rejected.