# AI Call: guide for AI agents API-first phone calls for AI agents. An AI agent can register for a person in seconds: send the person's name, email and the permissions you need; you get your token and its ID back immediately. The token does nothing until the person approves on a one-page form in their browser (no typing); then it goes live with exactly the approved permissions. With it you book calls that a voice agent places for the person, watch the two-sided transcript live, send the voice agent notes, transfer or end the call, and get the transcript and outcome back. AI Call runs no summarizer: you write your own summary from the transcript. Status: Live: registration, approvals, settings, docs, the MCP and calls (book, wait, note, answer, transfer, hang up, result, call page) with minutes metering (GET /api/v1/usage). call_transfer works on calls placed in LiveKit rooms (409 transfer_unavailable on the direct bridge). ## Register for a person (takes seconds, no browser needed on your side) Fastest, from a terminal (prints and saves your token and token ID; add --wait to block until the person approves): ```bash curl -fsSL https://aicall.prodevgroup.com/register.sh | bash -s -- --email jane@example.com --name "Jane Doe" --agent "Jane's assistant" --scopes calls:book_new,calls:coach,calls:hangup ``` Or the same thing as one HTTP call (any language): 1. **Ask.** `POST https://aicall.prodevgroup.com/api/v1/agent-access/requests` (no key needed) with JSON: ```json { "email": "jane@example.com", "name": "Jane Doe", "agentName": "Jane's assistant", "agentEmail": "assistant@example.com", "purpose": "Call vendors about open invoices", "requestedScopes": [ "calls:book_new", "calls:coach", "calls:hangup" ], "note": "Hi Jane, approve this and I will make the vendor calls for you." } ``` 2. The person gets an email with one page: their name (editable), a permission table (Permission | Asked | Approve | Deny) prefilled from your request, your note, and two call settings (email me a link when this assistant starts a call, on by default; the hours it may call). They tap Approve. Nothing is granted until then. 3. Until then every call with your token answers 403 token_pending_approval. Poll pollUrl every 30 to 60 seconds (tokenStatus becomes ACTIVE, status APPROVED), or simply retry; DECLINED or EXPIRED (7 days) means no. 4. Once approved the same token is live with exactly the permissions the person approved (they may approve fewer than you asked). Nothing to pick up. A new account is also approved by AI Call's operator: until then the token answers 403 account_pending_approval, and the person gets an email when it is approved. The operator decides what the account may use (voice engines, permissions, minutes per day and month, outbound calls only); the person may lock your token to some engines. aicall_me shows key.engines (the voiceModel values you may use) and key.outboundOnly. 5. Use the token as "Authorization: Bearer aic_live_..." on https://aicall.prodevgroup.com/api/v1 or as the bearer on the MCP endpoint https://aicall.prodevgroup.com/mcp. Keep the tokenId: it is how you refer to the token later (never send the token itself). Need more later? POST https://aicall.prodevgroup.com/api/v1/agent-access/changes with your token and the new requestedScopes; the person approves on the same one-page form; your token's permissions change in place. Lost your token? Ask the person to open the settings link from any AI Call email and tap "Show a replacement token" next to your name; it is shown to them once and they paste it to you. Same token ID and permissions; the old token stops working. ## Temporary keys (for chats and harnesses that cannot keep a secret) If your token would end up in a chat transcript or you have nowhere safe to keep it, ask for a temporary one: add "validForHours": 24 (any whole number from 1 to 168) to a new_account or new_token request. The token works for exactly that long after the person approves, then stops on its own (calls answer 401 token_expired). Ask again as often as you like; every approval is one tap. The response and pollUrl carry temporary, validForHours and tokenExpiresAt. ```json { "action": "new_token", "email": "jane@example.com", "name": "Jane Doe", "agentName": "Chat helper", "requestedScopes": [ "calls:book_approved" ], "validForHours": 24 } ``` ## Actions (field `action`) - `new_account`: first token for a person who has no account yet; token returned now, live after approval - `new_token`: another token on an existing account, for a different agent or application; token returned now, live after approval - `rotate_token`: fresh token with the same permissions returned now; one-tap confirm makes it live and stops the old one; needs tokenId - `update_permissions`: change what a token may do; needs tokenId and requestedScopes (one-tap approval) - `remove_tokens`: revoke tokens; tokenIds, or omit to let the person pick (one-tap confirm) Every action emails the person a one-page form. Default action is new_account for an unknown email, otherwise new_token. ## Limits POST /agent-access/requests is limited to 20 per minute per IP address, 10 per minute and 50 per day per person's email; POST /agent-access/changes to 3 per minute per token. Over the limit: 429 rate_limited with Retry-After. ## Permissions you can ask for - `calls:book_approved`: Call people you already approved. Place calls to numbers already on your approved list, to gather information only. The phone agent says it is your AI assistant. - `calls:book_new`: Call new numbers. Place calls to any number, including people you have not called through AI Call before. Each new number becomes an approved contact. - `calls:coach`: Coach a live call. Send notes to the phone agent during a call: background guidance, or a line for it to say next. - `calls:transfer`: Transfer calls. Hand a live call to you or to another number, with a hold line or at once. - `calls:hangup`: End calls. End a call: politely (the agent says goodbye) or at once. - `calls:listen`: Listen live and read call memory. Hear the audio of a call while it happens, from the call page, and read what AI Call remembers from earlier calls: each call's summary and transcript, and the notes on each number. - `calls:vault`: Use your vault on its calls. The phone agent on its calls may draw on your whole vault as the call needs it, each item the way you marked it: say it, send it, or keep it in mind without saying it. Ask-first items still wait for your OK. Without this, a call uses only the vault items its booking names. ## Calls Status: live. | Tool | REST | Permission | |---|---|---| | `call_book` | `POST /api/v1/calls` | calls:book_approved | calls:book_new | | `call_wait` | `GET /api/v1/calls/{bookingId}/events` | any active token (the one that booked) | | `call_note` | `POST /api/v1/calls/{bookingId}/notes` | calls:coach | | `call_transfer` | `POST /api/v1/calls/{bookingId}/transfer` | calls:transfer | | `call_hangup` | `POST /api/v1/calls/{bookingId}/hangup` | calls:hangup | | `call_result` | `GET /api/v1/calls/{bookingId}/result` | any active token (the one that booked) | | `call_card` | `POST /api/v1/calls/{bookingId}/card` | calls:coach | | `call_from_template` | `POST /api/v1/calls/from-template` | calls:book_approved | calls:book_new | | `call_templates` | `GET /api/v1/templates` | any active token | | `call_template` | `GET /api/v1/templates/{name}` | any active token | | `call_template_save` | `PUT /api/v1/templates/{name}` | calls:book_approved | calls:book_new | | `call_template_delete` | `DELETE /api/v1/templates/{name}` | calls:book_approved | calls:book_new | | `call_persona` | `GET /api/v1/persona` | any active token | | `call_persona_save` | `PUT /api/v1/persona` | any active token | | `call_profile` | `GET /api/v1/profile` | any active token | | `call_changelog` | `GET /api/v1/changelog` | any active token | | `call_file` | `GET /api/v1/calls/{bookingId}/files/{fileId}` | any active token (the one that booked, or the seat) | | `call_files` | `GET /api/v1/calls/{bookingId}/files` | any active token (the one that booked, or the seat) | | `call_profile_update` | `PATCH /api/v1/profile` | calls:book_approved | calls:book_new | | `call_upcoming` | `GET /api/v1/calls/upcoming` | any active token | | `call_link` | `GET /api/v1/calls/{bookingId}/link` | any active token (the one that booked) | | `call_answer` | `POST /api/v1/calls/{bookingId}/answers` | calls:coach | | `call_me` | `POST /api/v1/calls/me` | calls:book_approved | calls:book_new | | `call_dial` | `POST /api/v1/calls/{bookingId}/dial` | calls:book_approved | calls:book_new | | `call_mute` | `POST /api/v1/calls/{bookingId}/mute` | calls:coach | | `call_hold` | `POST /api/v1/calls/{bookingId}/hold` | calls:coach | | `call_voice` | `POST /api/v1/calls/{bookingId}/voice` | calls:coach | | `call_seat_away` | `POST /api/v1/calls/{bookingId}/seat/away` | calls:coach | | `call_memory` | `GET /api/v1/memory` | calls:listen | | `call_assistant` | `POST /api/v1/calls/{bookingId}/assistant` | calls:coach | | `call_text_owner` | `POST /api/v1/calls/{bookingId}/text-owner` | calls:coach | | `call_memory_read` | `GET /api/v1/memory/calls/{bookingId}` | calls:listen | - call_book needs calls:book_new for a new number, or calls:book_approved when the number is already an approved contact. The briefing (who, goal, facts, mayShare, neverShare, collect, successCriteria, openingLine) is limited to 9000 characters. idempotencyKey is required: a retry never dials twice. - A booking within your approved permissions dials; AI Call asks nobody per call. Calls outside the allowed hours the person set answer 409 outside_allowed_hours. - call_wait long-polls up to 15 seconds (waitMs) and returns events after your cursor: state, transcript (both sides, settled=false while a line may still grow), agent_state, note (with delivery state), question (the voice agent asks for help) and relay (it passed along an instruction or feedback from the call). The last call_wait after the call ends carries the result, with passedAlong listing every relay. - The call is your person's instruction layer (Sam, 2026-10-27): what they say on it is for you to act on while they are still on the line, not to read afterwards. Stay in call_wait for the whole call and act on relay events and on their own words as they come: call_voice switches the agent's voice live (it says a line in the new one and asks how it sounds), call_note steers it, a settings change lands at once. Run any other work in the background so you never leave the call, and get mid-call facts with your fastest model; dig deep only when your person asks you to. On a call to your person's own phone the agent can also switch its voice itself when they ask. - call_note mode guidance shapes the agent's next reply and is never read aloud; mode speak makes it say the line at the next pause. Notes queued before the call is answered are HELD until it is. - Read call_guide once: what makes a great call (a complete persona with quirks and history, clear objectives, real connection and local color) with samples to adapt. Then build calls from saved pieces: call_book with use: [a profile (who is calling and its house rules: business, errands, friends, family), a persona, a scene, a kind of call] and fill for their {blanks}; save your own pieces with call_template_save (kind profile, persona, scene or call). - Templates make any call quick: call_templates lists ready-made bookings with blanks (built-in starters: personal-checkin, get-me-someone, hold-for-me, order-and-pay, claim-followup, appointment; plus the person's own saved ones), call_from_template books one with {template, fill: {blank: value}, booking: {recipient, idempotencyKey, any call_book field to change}}, and call_template_save keeps a new or customized one for all of the person's agents. call_profile / call_profile_update read and change the account's call settings (company, the business persona's role and opener, home for the weather small talk, teams, voice, recording); never the person's phone or text line. - Pickup transfers (call_pickup, or call_book.handoff): for "get me on the phone with John at City Lumber" (mode reach: the voice agent gets past the front desk or phone menu to John, says one line and hands the call to the person) or "wait on hold with the IRS and give me the call when they answer" (mode hold: it says nothing while it holds and works the phone menu with keys or spoken answers, and the moment a live person answers it says one line and rings the person; no pickup and it asks them to hold and rings once more). The person gets a text to answer. Every call has a voicemail rule: message (default: who, why, the callback number), hangup, or transfer (rings the person to leave it themself; the default for pickup calls). The voice agent can also press phone-menu keys on any call. - Scheduling: call_book with scheduledAt (ISO 8601 with a UTC offset, 1 minute to 30 days ahead, inside the person's allowed hours) books the call for later; it waits as SCHEDULED and dials then. To be back in the seat on time, use any of: your own cron or scheduled task at wakeAt (the booking response carries wakeAt and a ready-made wakePrompt), a call.wake webhook (POST /api/v1/webhooks with events ["call.wake"]; fires wakeLeadSeconds before, default 120, with your seatBrief), or a long call_wait loop. requireSeat holds the dial until you have called call_wait for it after wakeAt (no show within seatGraceMinutes: cancelled, the person is told why). seatBrief is a private note to your future self, never told to the voice agent; call_upcoming lists your open calls with it. call_hangup cancels a scheduled call. Bookings for later need a token that lives past the call (409 token_expires_first). - call_me is for when your person says "give me a call": AI Call rings their phone, and from that call they reach whoever they want: dial (connected as soon as they pick up), their keypad (the number, then #), or call_dial from you. The whole call is recorded start to finish (their recording setting decides at the start; nothing pauses it) and transcribed live, each side under its own label (owner, caller). Stay in call_wait for the whole call and be their help in the background: look things up, add to the calendar, follow up, and reach them through your own channels or the call page, never on the line. The voice agent is on hand: agent muted puts it on the line from the start, listening only; ** on their keypad mutes or unmutes it; *8 on their keypad or call_hold has it take over a hold (silent until a live person is back, then it tells them one moment and brings your person back, ringing their phone if they hung up); a text from your person to the line, or call_mute false plus a call_note, has it act. call_mute works on any answered call: muted, the agent keeps listening and says nothing. callerId mine (default): the people they call see the person's own cell once it is a verified caller ID with the carrier, else AI Call's number. call_wait shows control events (dial DIALING, CONNECTED, NO_ANSWER, BUSY, FAILED, ENDED; mute ON, OFF; hold HOLDING, BACK, ENDED; agent JOINED, LEFT). - call_transfer hands the answered call to target "owner" (the person's phone) or an E.164 number already on their approved list. soft (warm): the agent tells them to hold a moment, hold music plays while the target rings, and when the target picks up the agent briefs them privately (who is on the line, what they want, where it stands) while the caller still hears only the hold music; instant (cold): hold music at once, connected the moment the target answers. Once connected the agent steps out and the two talk (recorded, each side transcribed under its own speaker label: caller, owner, transfer:); if not, the agent comes back, promises a callback and carries on. call_wait shows control events (action transfer, state DIALING, CONNECTED, NO_ANSWER, BUSY or UNAVAILABLE). Only calls placed in LiveKit rooms can transfer; the errors are 409 call_not_connected, call_ended, transfer_unavailable and no_owner_phone, and 403 transfer_target_not_approved. - call_result returns the transcript (both sides, timestamps), the notes that were injected and when, the outcome from the carrier (answered, no answer, busy, failed, who hung up, duration) and the call's billable minutes {callee, transfer, agent}. The same goes by email to you (agentEmail) and to the person. ## Usage (minutes) `GET /api/v1/usage?month=YYYY-MM` (any active token). GET /api/v1/usage returns the minutes used by the person your token acts for in a UTC calendar month: totals, split by call engine, and per token (every token the person holds: tokenId and agentName). It is REST only; there is no MCP tool for it yet. Answered calls count once they have ended, in the month they were answered. Each call has three legs, each rounded up to a whole minute: callee (answered to ended), transfer (the target connected to ended; 0 without a transfer) and agent (the voice agent on the line: answered to the handover, or to the end). call_result carries the same three numbers for one call as minutes. AI Call counts minutes; it does not price them. ## After you have a token - API docs: https://aicall.prodevgroup.com/api/v1/docs - OpenAPI: https://aicall.prodevgroup.com/api/v1/openapi.json - MCP (Streamable HTTP, bearer = your token): https://aicall.prodevgroup.com/mcp - Who am I: GET https://aicall.prodevgroup.com/api/v1/me JSON version of this guide: https://aicall.prodevgroup.com/api/v1/agent-access