{"openapi":"3.1.0","info":{"title":"AI Call API","description":"API-first phone calls for AI agents. Authenticate with an agent token: `Authorization: Bearer aic_live_...`. Every error is `{\"error\":{\"code\",\"message\"}}`. Scopes: calls:book_approved, calls:book_new, calls:coach, calls:transfer, calls:hangup, calls:listen, calls:vault. AI agents without a token: register for a person in seconds with POST /api/v1/agent-access/requests (no auth). You get your token and its ID at once; it answers 403 token_pending_approval until the person approves on a one-page form, then the same token is live with exactly the approved permissions. Full guide: GET /api/v1/agent-access or /for-agents. Calls are live, call_transfer included (calls placed in LiveKit rooms), and GET /api/v1/usage reports the minutes used per month.","version":"0.1.0"},"servers":[{"url":"https://aicall.prodevgroup.com"}],"paths":{"/api/v1/agent-access":{"get":{"tags":["Agent access"],"summary":"Guide for AI agents: how to register for a person in seconds (no key needed)","description":"Plain JSON explaining the whole process: ask by email, you get your token at once, the person approves on a one-page form and the same token goes live. Also at /for-agents (HTML) and /llms.txt (Markdown).","operationId":"agent_guide_api_v1_agent_access_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"public","security":[]}},"/api/v1/agent-access/requests":{"post":{"tags":["Agent access"],"summary":"Ask a person for permission to act on their behalf (no API key needed); the token is returned right away","description":"For agents with or without a token. You get apiKey and tokenId in this response immediately. The token does nothing (every call answers 403 token_pending_approval) until the person, who gets an email with a one-page approval, ticks the permissions and approves. Then it goes live with exactly the approved permissions; poll pollUrl or just retry. Works even if the person never logs in. Rate limited per IP and per email.","operationId":"create_access_request_api_v1_agent_access_requests_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessRequestBody"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessRequestView"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"public","security":[]}},"/api/v1/agent-access/requests/{request_id}":{"get":{"tags":["Agent access"],"summary":"Status of an access request (with its poll secret)","description":"Use the pollUrl from the creation response. When status is APPROVED and tokenStatus ACTIVE, the token you already hold is live. DECLINED or EXPIRED (7 days) means no.","operationId":"access_request_status_api_v1_agent_access_requests__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","maxLength":80,"title":"Request Id"}},{"name":"secret","in":"query","required":true,"schema":{"type":"string","minLength":16,"maxLength":200,"title":"Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessRequestView"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"public","security":[]}},"/api/v1/agent-access/changes":{"post":{"tags":["Agent access"],"summary":"Ask the token owner to change this token's permissions","description":"Emails the person who owns the calling token a one-page approval with the new permissions. On approval the token's permissions change in place. Any scope is accepted here; the person decides. 3 per minute per token.","operationId":"create_change_request_api_v1_agent_access_changes_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeRequestBody"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessRequestView"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/me":{"get":{"tags":["Account"],"summary":"Who am I","description":"The person, token and call settings behind the bearer.","operationId":"me_api_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeView"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/calls":{"post":{"tags":["Calls"],"summary":"Book a call (call_book)","description":"MCP tool call_book. Books an outbound call; the voice agent dials within seconds, or at scheduledAt (up to 30 days ahead; you are woken wakeLeadSeconds before by the call.wake webhook, and the response's wakeAt and wakePrompt are for your own cron; requireSeat holds the dial until you call_wait it). call_hangup cancels a scheduled call. Within your approved permissions it dials: no per-call approval. calls:book_new for any number (it becomes an approved contact), calls:book_approved for numbers already on the person's approved list. The briefing has two sides: details (shareable) and history (private, never voiced); playbooks say how to handle the call (intent, never lines). Refused with 409 outside_allowed_hours outside the hours the person set; at most 5 bookings per hour per key. The response carries callLink, the live call page; paste it to your human.","operationId":"call_book_api_v1_calls_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallBookRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallBooking"}}}},"409":{"description":"outside_allowed_hours, idempotency_conflict, no_caller_id, too_many_live_calls","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"recipient_not_approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/calls/from-template":{"post":{"tags":["Calls"],"summary":"Book a call from a template (call_from_template)","description":"MCP tool call_from_template. Fills a template's blanks from fill, lays booking (recipient, idempotencyKey and any call_book field you want to change) on top, and books it exactly like call_book. A missing required blank answers 400 naming it.","operationId":"call_from_template_api_v1_calls_from_template_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FromTemplate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallBooking"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/call-guide":{"get":{"tags":["Calls"],"summary":"How to set up a great call (call_guide)","description":"MCP tool call_guide. Read once: what makes a great call (a complete persona, clear objectives, real connection and local color), samples to adapt, and how to save the pieces with {blanks} so the next call only fills them in.","operationId":"call_guide_api_v1_call_guide_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"none","security":[{"bearerAuth":[]}]}},"/api/v1/templates":{"get":{"tags":["Calls"],"summary":"Call templates (call_templates)","description":"MCP tool call_templates. The built-in starters and the person's own saved templates (a saved one wins over a built-in of the same name): name, description, fields (the blanks), origin.","operationId":"list_templates_api_v1_templates_get","parameters":[{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"enum":["profile","persona","scene","call"],"type":"string"},{"type":"null"}],"description":"Only this kind","title":"Kind"},"description":"Only this kind"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/templates/{name}":{"get":{"tags":["Calls"],"summary":"One template (call_template)","description":"MCP tool call_template. The whole template: its blanks and the call_book body it fills in.","operationId":"get_template_api_v1_templates__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","maxLength":48,"title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]},"put":{"tags":["Calls"],"summary":"Save a template (call_template_save)","description":"MCP tool call_template_save. Saves (or replaces) one of the person's templates, for all their agents: {description, fields: [{name, about, required}], booking: call_book fields whose strings may hold {blanks}}. fields left out: every blank is required. Saving a built-in's name customizes it for this person.","operationId":"save_template_api_v1_templates__name__put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","maxLength":48,"title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]},"delete":{"tags":["Calls"],"summary":"Delete a saved template (call_template_delete)","description":"MCP tool call_template_delete. Deletes one of the person's saved templates (a built-in of the same name comes back).","operationId":"delete_template_api_v1_templates__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","maxLength":48,"title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/stories":{"get":{"tags":["Calls"],"summary":"Call stories (call_story)","description":"MCP tool call_story. The person's call stories: one per number and direction (out: calls to that number, in: calls from it), each how the calls that went well with that place go, what made them work and the lessons learned. With number: that number's stories in full ({number, stories: [{direction, place, story, chars, updatedAt, updatedBy}]}; 404 when there is none); without: the list, without the text. The voice agent gets the story up front on every call out to that number, or in from it, and when it is dialed into a call.","operationId":"get_stories_api_v1_stories_get","parameters":[{"name":"number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B)","title":"Number"},"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B)"},{"name":"direction","in":"query","required":false,"schema":{"anyOf":[{"enum":["out","in"],"type":"string"},{"type":"null"}],"description":"out: the calls AI Call makes to that number; in: the calls that come in from it (default: both)","title":"Direction"},"description":"out: the calls AI Call makes to that number; in: the calls that come in from it (default: both)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"not_found: no story for that number (and direction)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:listen","security":[{"bearerAuth":[]}]},"put":{"tags":["Calls"],"summary":"Save a call story (call_story_save)","description":"MCP tool call_story_save. Saves the story for one number and direction, replacing the one before (kept in the audit log): {number, direction out|in, place, story}. Write it after a call that went well or taught something, whole: who they are and how they answer, how the call goes step by step, how to say each thing, what went wrong before and how to prevent it, what to check before hanging up. At most 12000 characters: the voice agent reads all of it on every call.","operationId":"save_story_api_v1_stories_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]},"delete":{"tags":["Calls"],"summary":"Delete a call story (call_story_save remove)","description":"MCP tool call_story_save. With remove: deletes the story for one number and direction (kept in the audit log).","operationId":"delete_story_api_v1_stories_delete","parameters":[{"name":"number","in":"query","required":true,"schema":{"type":"string","description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B)","title":"Number"},"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B)"},{"name":"direction","in":"query","required":true,"schema":{"enum":["out","in"],"type":"string","description":"out: the calls AI Call makes to that number; in: the calls that come in from it","title":"Direction"},"description":"out: the calls AI Call makes to that number; in: the calls that come in from it"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/records":{"get":{"tags":["Calls"],"summary":"Place records (call_records)","description":"MCP tool call_records. What the person ordered, asked for, booked or paid with each place, and how it came out, newest first: {records: [{recordId, number, place, direction, kind, at, summary, items, total, result, bookingId, source, updatedAt}]}. AI Call writes one by itself a few seconds after each real call (source call); agents add or fix them (source agent). With number: that place's; kind narrows it; q: every word must appear (an item, a place, a result). The voice agent gets a place's latest records on every call there, under its story.","operationId":"get_records_api_v1_records_get","parameters":[{"name":"number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B). Only that place's records","title":"Number"},"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B). Only that place's records"},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"enum":["order","lookup","booking","payment","issue","other"],"type":"string"},{"type":"null"}],"description":"order, lookup (stock, price, hours, a prescription or order status), booking, payment, issue (a complaint, refund, credit, something missing or wrong) or other","title":"Kind"},"description":"order, lookup (stock, price, hours, a prescription or order status), booking, payment, issue (a complaint, refund, credit, something missing or wrong) or other"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"Words that must all appear, e.g. Cajun, Zelda, refill","title":"Q"},"description":"Words that must all appear, e.g. Cajun, Zelda, refill"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:listen","security":[{"bearerAuth":[]}]},"put":{"tags":["Calls"],"summary":"Add or fix a place record (call_record_save)","description":"MCP tool call_record_save. Adds a record ({number, kind, summary, items, total, result, at, place, direction, bookingId}), or with recordId changes the fields given on one (what the call could not know: the receipt's prices, the real total, what happened after). The record before is kept in the audit log.","operationId":"save_record_api_v1_records_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/records/{recordId}":{"delete":{"tags":["Calls"],"summary":"Delete a place record (call_record_save remove)","description":"MCP tool call_record_save. With remove: deletes one record (kept in the audit log).","operationId":"delete_record_api_v1_records__recordId__delete","parameters":[{"name":"recordId","in":"path","required":true,"schema":{"type":"string","pattern":"^rc_[0-9a-f]{16}$","title":"Recordid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/vault":{"get":{"tags":["Calls"],"summary":"The person's vault items, by name (call_vault)","description":"MCP tool call_vault. The details the person keeps in their vault, by name (alt ID), with askFirst and showInTranscript: {items, note}. Never the values. Name the ones a call may use in its booking's vault list; the voice agent gets a value only when it needs it on that call.","operationId":"get_vault_api_v1_vault_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/vault/read":{"get":{"tags":["Calls"],"summary":"Read one vault item (call_vault_read)","description":"MCP tool call_vault_read. The value of one item in the person's vault, for you (the seat) only: {status, altId, kind, value | card | fileName..., use}. Needs calls:vault. An ask-first item opens only during a live call (bookingId), once the person approves it there: until then {status: awaiting_approval}. Give the voice agent a value with {{vault:<name>}} in call_answer or call_note.","operationId":"read_vault_api_v1_vault_read_get","parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","title":"Name"}},{"name":"bookingId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bookingid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:vault","security":[{"bearerAuth":[]}]}},"/api/v1/persona":{"get":{"tags":["Calls"],"summary":"Your own persona (call_persona)","description":"MCP tool call_persona. The character you, this agent, play on the calls you book: {persona: {name, persona, vibe, voice} or null, nameOnCalls}. Each agent has its own.","operationId":"get_persona_api_v1_persona_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]},"put":{"tags":["Calls"],"summary":"Save your own persona (call_persona_save)","description":"MCP tool call_persona_save. Saves the character you play on your calls: {name (the first name you go by; never a model name, never anything labelled assistant), persona (background, quirks, how you talk, a bit of history, local ties), vibe, voice (else matched to the name)}. Replaces your previous one; update it as you learn what works.","operationId":"save_persona_api_v1_persona_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/changelog":{"get":{"tags":["Calls"],"summary":"Changes to the person's profile and their agents' personas (call_changelog)","description":"MCP tool call_changelog. Newest first: {items: [{id, at, kind: profile | persona, agent (whose persona: tokenId, name), by {type: agent | operator, name, tokenId?}, changes: [{field, from, to}]}]}. Every change made through call_profile_update, call_persona_save or the server's command line is here. The person's own numbers show only their last four digits.","operationId":"get_changelog_api_v1_changelog_get","parameters":[{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"enum":["profile","persona"],"type":"string"},{"type":"null"}],"description":"only profile or only persona changes","title":"Kind"},"description":"only profile or only persona changes"},{"name":"tokenId","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^tok_[0-9a-f]{16}$"},{"type":"null"}],"description":"only this agent's persona","title":"Tokenid"},"description":"only this agent's persona"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/profile":{"get":{"tags":["Calls"],"summary":"The person's call profile (call_profile)","description":"MCP tool call_profile. company, the business persona (role, team, opener, vibe), home (place, lat, lon, timezone: the weather small talk), teams and feeds (small talk), voice, recording; and whether a phone and text line are on file.","operationId":"get_profile_api_v1_profile_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]},"patch":{"tags":["Calls"],"summary":"Update the person's call profile (call_profile_update)","description":"MCP tool call_profile_update. Changes only the settings you send (null removes one; persona and home merge key by key). Never the person's phone or text line: they set those themselves. Audited.","operationId":"update_profile_api_v1_profile_patch","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/events":{"get":{"tags":["Calls"],"summary":"Wait for call events (call_wait)","description":"MCP tool call_wait. Long-polls up to waitMs (max 15000) and returns the events after your cursor: state, transcript (both sides; settled lines by default, view=all adds the provisional ones), agent_state, note, question (answer it with call_answer), text, control. A late joiner replays from after=0. The last call_wait after the call ends carries result.","operationId":"call_wait_api_v1_calls__bookingId__events_get","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"},{"name":"after","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Return events with seq greater than this (0 = from the start)","default":0,"title":"After"},"description":"Return events with seq greater than this (0 = from the start)"},{"name":"waitMs","in":"query","required":false,"schema":{"type":"integer","maximum":15000,"minimum":0,"description":"How long to wait for new events, 0 to 15000 ms","default":15000,"title":"Waitms"},"description":"How long to wait for new events, 0 to 15000 ms"},{"name":"view","in":"query","required":false,"schema":{"enum":["settled","all"],"type":"string","description":"settled (default): transcript lines once final; all: provisional lines too","default":"settled","title":"View"},"description":"settled (default): transcript lines once final; all: provisional lines too"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallEvents"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token (the one that booked)","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/seat/away":{"post":{"tags":["Calls"],"summary":"Step out of the seat for a moment (call_seat_away)","description":"MCP tool call_seat_away. For the seat on an incoming call that has to leave it briefly, for example to hand a task to another of your person's bots. AI Call wakes you again at once (reason back) instead of after a minute; when you are back, read the call from the start (call_wait after=0) before you carry on. Prefer staying on the call. 10 per call.","operationId":"call_seat_away_api_v1_calls__bookingId__seat_away_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallSeatAwayRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeatAway"}}}},"403":{"description":"not_the_seat","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/notes":{"post":{"tags":["Calls"],"summary":"Send the phone agent a note (call_note)","description":"MCP tool call_note. guidance: worked in where it fits, never read aloud; speak: said at the next pause (after the other person finishes and the agent's audio has played out). kind detail = information it may share; kind private = guidance for its judgment, never voiced. Say what to change from now on, not a line to say (it copies lines word for word). HELD until the call is answered. The person's own notes outrank yours. 1 note per 2 seconds, 60 per call.","operationId":"call_note_api_v1_calls__bookingId__notes_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallNoteRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteQueued"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/assistant":{"post":{"tags":["Calls"],"summary":"Add your own line to the call's transcript (call_assistant)","description":"MCP tool call_assistant. Your line in the call's transcript, shown on the call page and in the email as yours and never spoken on the call. doing true: what you are doing now (\"Looking up the drive from Madison to Decatur\"); false: what you found (\"You have a meeting Thursday at 11; the two sites are 45 minutes apart\"). Up to ten minutes after the call ends; 200 per call.","operationId":"call_assistant_api_v1_calls__bookingId__assistant_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallAssistantRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantLine"}}}},"409":{"description":"call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/text-owner":{"post":{"tags":["Calls"],"summary":"Text the person what you found (call_text_owner)","description":"MCP tool call_text_owner. Texts your person (only them, from their text line, signed with your name) what you found during the call, and adds the same line to the transcript. Short and useful: what you found, not what you are about to do. One text every 5 seconds, 40 per call; 409 no_text_line when they have none.","operationId":"call_text_owner_api_v1_calls__bookingId__text_owner_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallTextOwnerRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerText"}}}},"409":{"description":"no_text_line, call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/answers":{"post":{"tags":["Calls"],"summary":"Answer the phone agent's question (call_answer)","description":"MCP tool call_answer. Answers the phone agent's ask_for_help question (a question event in call_wait). Facts only: the agent relays it as something it just found, exactly as given; put instructions in call_note instead. The first answer wins (you, the person by text, or the person on the call page); the person is told when you answered.","operationId":"call_answer_api_v1_calls__bookingId__answers_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallAnswerRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnswerAccepted"}}}},"409":{"description":"no_open_question, call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/transfer":{"post":{"tags":["Calls"],"summary":"Transfer the call (call_transfer)","description":"MCP tool call_transfer. 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, they hear hold music while the target rings, and when the target picks up the agent briefs them privately (who is on the line, what they want) before connecting; instant (cold): hold music at once, connected the moment the target answers. Then the agent steps out and the two talk (recorded, each side transcribed under its own label); if not, the agent comes back, promises a callback and carries on. Watch call_wait for control events (transfer DIALING, CONNECTED, NO_ANSWER, BUSY). Calls in LiveKit rooms only (409 transfer_unavailable on the direct bridge).","operationId":"call_transfer_api_v1_calls__bookingId__transfer_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallTransferRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ControlAccepted"}}}},"409":{"description":"call_not_connected, call_ended, transfer_unavailable, no_owner_phone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"transfer_target_not_approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:transfer","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/card":{"post":{"tags":["Calls"],"summary":"Send the card for a payment (call_card)","description":"MCP tool call_card. Only when the voice agent asked for it (a payment event with state NEEDED in call_wait, or the call.payment webhook): the card it reads to the other side to pay. Held in memory for that payment only; never stored, logged, recorded or returned. The recording pauses and numbers are masked in the transcript while it is out. 409 no_payment_request otherwise.","operationId":"call_card_api_v1_calls__bookingId__card_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"409":{"description":"no_payment_request, call_not_live","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/card-drop/{bookingId}/{token}":{"post":{"tags":["Calls"],"summary":"Drop the card for one payment (single-use link)","description":"The cardDropUrl from a payment event or the call.payment webhook: POST the card ({number, exp, cvc, zip?, name?}) here, with no token, while the voice agent is waiting for it (10 minutes at most, one use). Meant for a script that reads the card from a vault, so no AI ever sees it. 404 once the link is used, expired or not the open request.","operationId":"card_drop_api_v1_card_drop__bookingId___token__post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"},{"name":"token","in":"path","required":true,"schema":{"type":"string","maxLength":80,"title":"Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"none: the link is the permission","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/hangup":{"post":{"tags":["Calls"],"summary":"End the call (call_hangup)","description":"MCP tool call_hangup. soft: the agent closes the call in a sentence or two and the line drops after at most 45 s; hard: drops now. A call not dialed yet is cancelled.","operationId":"call_hangup_api_v1_calls__bookingId__hangup_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallHangupRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ControlAccepted"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:hangup","security":[{"bearerAuth":[]}]}},"/api/v1/calls/me":{"post":{"tags":["Calls"],"summary":"Ring the person for their own call (call_me)","description":"MCP tool call_me. 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: stay in call_wait and be their help in the background (look things up, add to the calendar, follow up), reaching 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; ** on their keypad mutes or unmutes it; *8 on their keypad or call_hold has it take over a hold (it says nothing until a live person is back, then 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, has it speak. callerId mine: the people they call see their own cell (once verified with the carrier; until then AI Call's number). The call to them always shows AI Call's number.","operationId":"call_me_api_v1_calls_me_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallMeRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallBooking"}}}},"409":{"description":"no_owner_phone, outside_allowed_hours, idempotency_conflict, too_many_live_calls","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"recipient_not_approved (dial)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/dial":{"post":{"tags":["Calls"],"summary":"Ring someone into a call_me call (call_dial)","description":"MCP tool call_dial. On a call_me call your person is on: rings number into it, from their own cell when callerId is mine and it is verified. One other party at a time. Watch call_wait for control events (dial DIALING, CONNECTED, NO_ANSWER, BUSY, FAILED).","operationId":"call_dial_api_v1_calls__bookingId__dial_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallDialRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ControlAccepted"}}}},"409":{"description":"not_call_me, call_not_connected, call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"recipient_not_approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:book_approved | calls:book_new","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/mute":{"post":{"tags":["Calls"],"summary":"Mute or unmute the voice agent (call_mute)","description":"MCP tool call_mute. muted true: the voice agent keeps listening (the call is still transcribed) and says nothing, until muted false. On a call_me call, muted false brings it onto the line if it is not there yet; send a call_note with what you want it to do. Watch call_wait for control events (mute ON, OFF).","operationId":"call_mute_api_v1_calls__bookingId__mute_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallMuteRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ControlAccepted"}}}},"409":{"description":"call_not_connected, call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/hold":{"post":{"tags":["Calls"],"summary":"Have the voice agent take a hold (call_hold)","description":"MCP tool call_hold. On a call_me call where the other side put your person on hold: the voice agent takes over and says nothing (not to music, recordings or menus) until a live person is back, then tells them one moment (tellThem) and brings your person back: if they are still on the line they hear it, if they hung up their phone rings. Same as *8 on their keypad. Watch call_wait for control events (hold HOLDING, BACK).","operationId":"call_hold_api_v1_calls__bookingId__hold_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallHoldRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ControlAccepted"}}}},"409":{"description":"not_call_me, call_not_connected, call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/voice":{"post":{"tags":["Calls"],"summary":"Switch the voice agent's voice live (call_voice)","description":"MCP tool call_voice. The voice agent speaks in another voice from its next sentence, on this call only (the booking, persona and profile keep theirs: change those with call_profile_update or call_template_save). After a switch it says a line or two in the new voice and asks how it sounds. Use it when your person asks for a different voice on the call, or in a relay event. Watch call_wait for the control event (voice CHANGED). On a call to your person's own phone the agent can also switch itself when they ask. With voiceModel (grok or qwen) the call moves to that engine to compare voices: it picks up a second or two later with the call so far in writing; watch for the control event (voice_model SWITCHED or FAILED).","operationId":"call_voice_api_v1_calls__bookingId__voice_post","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallVoiceRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ControlAccepted"}}}},"409":{"description":"call_not_connected, call_ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/files":{"get":{"tags":["Calls"],"summary":"The call's photos, files and camera frames (call_files)","description":"MCP tool call_files. Newest first by limit (default 20, up to 100), returned oldest first so camera frames read as a sequence: {files[] {fileId, name, type, size, at, secondsIntoCall, source camera|page, url}}. source camera: frames (about one a second) and photos from the camera link the voice agent texted; page: what your person sent you from the call page. Line them up with the transcript by at.","operationId":"call_files_api_v1_calls__bookingId__files_get","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(camera|page)$"},{"type":"null"}],"title":"Source"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallFiles"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token (the one that booked, or the seat)","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/files/{fileId}":{"get":{"tags":["Calls"],"summary":"A photo or file the person sent the seat (call_file)","description":"MCP tool call_file. The bytes of a photo or file your person sent you from the call page: a relay event in call_wait with file {fileId, name, type, size, url}. Read it and use it for the call (a document to check, a photo of damage, a claim letter).","operationId":"call_file_api_v1_calls__bookingId__files__fileId__get","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"},{"name":"fileId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","title":"Fileid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token (the one that booked, or the seat)","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/result":{"get":{"tags":["Calls"],"summary":"Transcript and outcome (call_result)","description":"MCP tool call_result. The durable record: outcome from the carrier (answered, no answer, busy, failed), who hung up, duration, the notes injected and when, the agent's questions with their answers, texts, and the transcript of both sides with timestamps. No summary: write your own.","operationId":"call_result_api_v1_calls__bookingId__result_get","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallResult"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token (the one that booked)","security":[{"bearerAuth":[]}]}},"/api/v1/calls/upcoming":{"get":{"tags":["Calls"],"summary":"Your calls not finished yet (call_upcoming)","description":"MCP tool call_upcoming. Scheduled, queued and live calls booked with this token, soonest first, each with your seatBrief (the note you left yourself when booking). Call it when you wake for a scheduled call, then call_wait the booking.","operationId":"call_upcoming_api_v1_calls_upcoming_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpcomingCalls"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/calls/{bookingId}/link":{"get":{"tags":["Calls"],"summary":"The live call page (call_link)","description":"MCP tool call_link. https://aicall.prodevgroup.com/call/<token>: live transcript, notes, questions, hang up, listen; read-only for 30 days after the call. Paste it to your human.","operationId":"call_link_api_v1_calls__bookingId__link_get","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallLinkView"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token (the one that booked)","security":[{"bearerAuth":[]}]}},"/api/v1/memory":{"get":{"tags":["Memory"],"summary":"What AI Call remembers about a number (call_memory)","description":"MCP tool call_memory. What AI Call remembers about a phone number for the person your token acts for: the running summary of everything with them (who they are, claim and account numbers, what is still agreed, owed or open) and the call history, newest first, each call's summary (authorizations, agreements, issues, key details, next steps; never its transcript). Memory is kept per person and number from their finished calls; the phone agent reads the same notes on its own calls. Use it before calling someone or when a call turns to them. Open one call with call_memory_read. The MCP tool also takes a query and then returns matches, the list GET /memory/search gives for that number.","operationId":"call_memory_api_v1_memory_get","parameters":[{"name":"number","in":"query","required":true,"schema":{"type":"string","description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B)","title":"Number"},"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B)"},{"name":"rolePlay","in":"query","required":false,"schema":{"type":"boolean","description":"true: the role-play memory, kept apart from real calls (practice calls, booked with rolePlay)","default":false,"title":"Roleplay"},"description":"true: the role-play memory, kept apart from real calls (practice calls, booked with rolePlay)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallMemory"}}}},"404":{"description":"not_found: nothing is remembered about that number yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:listen","security":[{"bearerAuth":[]}]}},"/api/v1/memory/calls/{bookingId}":{"get":{"tags":["Memory"],"summary":"Open one earlier call (call_memory_read)","description":"MCP tool call_memory_read. One earlier call from call_memory: its summary (authorizations, agreements, issues, key details, next steps) first, its condensed transcript (part transcript, only what was said while that number was on the line) only when you need more. A call that had several numbers on the line is kept once per number: pass number for the one you want, else the latest. 404 when the call is not in memory (a call is written up once it ends).","operationId":"call_memory_read_api_v1_memory_calls__bookingId__get","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","description":"bookingId from call_book","title":"Bookingid"},"description":"bookingId from call_book"},{"name":"part","in":"query","required":false,"schema":{"enum":["summary","transcript"],"type":"string","description":"summary (default), or transcript: the condensed transcript","default":"summary","title":"Part"},"description":"summary (default), or transcript: the condensed transcript"},{"name":"number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B). Only that number's side of the call","title":"Number"},"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B). Only that number's side of the call"},{"name":"rolePlay","in":"query","required":false,"schema":{"type":"boolean","description":"true: the role-play memory, kept apart from real calls (practice calls, booked with rolePlay)","default":false,"title":"Roleplay"},"description":"true: the role-play memory, kept apart from real calls (practice calls, booked with rolePlay)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallMemoryRead"}}}},"404":{"description":"not_found: that call is not in memory","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:listen","security":[{"bearerAuth":[]}]}},"/api/v1/memory/search":{"get":{"tags":["Memory"],"summary":"Search every earlier call (call_memory query)","description":"MCP tool call_memory. With a query, the earlier calls whose words best match, best first (at most 5): each with the matching words. It searches every word of every call's transcript and summary, all of the person's numbers, or only number. Open a match with call_memory_read.","operationId":"call_memory_search_api_v1_memory_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":300,"description":"The words to look for: names, amounts, claim numbers, what was agreed","title":"Q"},"description":"The words to look for: names, amounts, claim numbers, what was agreed"},{"name":"number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B). Only the calls with that number (default: all of them)","title":"Number"},"description":"E.164 phone number, e.g. +12565550123 (in a URL write the + as %2B). Only the calls with that number (default: all of them)"},{"name":"rolePlay","in":"query","required":false,"schema":{"type":"boolean","description":"true: the role-play memory, kept apart from real calls (practice calls, booked with rolePlay)","default":false,"title":"Roleplay"},"description":"true: the role-play memory, kept apart from real calls (practice calls, booked with rolePlay)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemorySearch"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:listen","security":[{"bearerAuth":[]}]}},"/api/v1/usage":{"get":{"tags":["Usage"],"summary":"Call minutes for a month (usage)","description":"Minutes metered for the person your token acts for, over a UTC calendar month (month=YYYY-MM, default the current month): totals, split by call engine, and per token (every token the person holds, not just yours; token IDs and agent names only). Answered calls count once they have ended, in the month they were answered. Three legs per call, 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.","operationId":"usage_api_v1_usage_get","parameters":[{"name":"month","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[0-9]{4}-(0[1-9]|1[0-2])$"},{"type":"null"}],"description":"UTC calendar month, YYYY-MM (default: the current month)","title":"Month"},"description":"UTC calendar month, YYYY-MM (default: the current month)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageView"}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token (the person's whole account)","security":[{"bearerAuth":[]}]}},"/api/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List this token's webhooks","operationId":"list_webhooks_api_v1_webhooks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a webhook for this token's calls","description":"Deliveries are JSON POSTs {id, event, createdAt, data} with headers x-aicall-signature (sha256=HMAC-SHA256(secret, \"<timestamp>.<raw body>\")), x-aicall-timestamp, x-aicall-event and x-aicall-delivery (Pro Sign's scheme). Events: call.connected, call.question (the phone agent asked for help: answer with call_answer), call.relay (the phone agent passed along an instruction or feedback from the call: act on it), call.ended (data = call_result), and call.seat (only when listed; needs calls:listen and calls:coach): it makes this token one of the person's seats, and an incoming call that needs one is handed to the first free seat with data {callId, bookingId, reason: ring | next | rejoin, seat}; take the seat with call_wait on callId until the call ends (a seat that has not joined within a minute is passed over, one that left is woken again). With bearer the receiver also gets Authorization: Bearer <bearer>. Failed deliveries are retried with backoff for about a day. The secret is only returned here.","operationId":"create_webhook_api_v1_webhooks_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookBody"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/webhooks/{webhookId}":{"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook_api_v1_webhooks__webhookId__delete","parameters":[{"name":"webhookId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$","title":"Webhookid"}}],"responses":{"204":{"description":"Successful Response"},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]}},"/api/v1/seat/wakeup":{"get":{"tags":["Webhooks"],"summary":"This token's wake-up for incoming calls","description":"{active, request}: the wake-up in use (kind email or webhook) and the latest request with its status (PENDING, APPROVED, DECLINED, REPLACED, EXPIRED).","operationId":"seat_wakeup_status_api_v1_seat_wakeup_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"any active token","security":[{"bearerAuth":[]}]},"post":{"tags":["Webhooks"],"summary":"Ask to be woken for the person's incoming calls","description":"Makes this token one of the person's seats once the person approves (an email with a one-tap approval page, as for tokens). Send email (your own address) or url and key. When an incoming call needs a seat and this one is free, AI Call sends {callId, bookingId, reason: ring | next | rejoin, seat, caller: {number, name}} there: an email with subject \"AI Call seat: <callId>\" and a caller: line, or a call.seat webhook. call_wait carries caller too. Take the seat with call_wait on callId until the call ends (a seat that has not joined within a minute is passed over, one that left is woken again). A new request replaces one still waiting; once approved it replaces the token's wake-up. 5 per hour per token.","operationId":"seat_wakeup_request_api_v1_seat_wakeup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeatWakeupBody"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized (missing, unknown, revoked) or token_expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"token_pending_approval (the person has not approved yet) or insufficient_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"calls:listen and calls:coach","security":[{"bearerAuth":[]}]}},"/api/v1/small-talk/topics":{"get":{"tags":["Calls"],"summary":"Small-talk topics for call_book.smallTalk","description":"The bank of everyday topics the phone agent can use in a lull (a topic and an angle, never a line). Pass ids in call_book.smallTalk, or your own topic as text. Live items (home weather, the person's teams, holidays) are added on their own.","operationId":"small_talk_topics_api_v1_small_talk_topics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid_request: the first problem, as '<field>: <issue>'","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-scope":"public","security":[]}}},"components":{"schemas":{"AccessRequestBody":{"properties":{"action":{"anyOf":[{"type":"string","enum":["new_account","new_token","rotate_token","update_permissions","remove_tokens"]},{"type":"null"}],"title":"Action","description":"What you ask for. Default: new_account when the email has no account yet, otherwise new_token. rotate_token/update_permissions need tokenId; remove_tokens takes tokenIds (omit to let the person pick). Each sends the person a one-page form."},"tokenId":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Tokenid","description":"For rotate_token / update_permissions: the token ID (never the token itself)"},"tokenIds":{"anyOf":[{"items":{"type":"string","maxLength":80},"type":"array","maxItems":100},{"type":"null"}],"title":"Tokenids","description":"For remove_tokens: token IDs to remove"},"email":{"type":"string","title":"Email","description":"The person who will own the token and approve by email"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name","description":"The person's name (required; used in the greeting and for their account)"},"agentName":{"anyOf":[{"type":"string","maxLength":80,"minLength":2},{"type":"null"}],"title":"Agentname","description":"How the assistant introduces itself (optional; default \"<Name>'s AI assistant\"); the person sees this, e.g. \"Lori (front desk)\""},"agentEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agentemail","description":"The assistant's own email: where call links and transcripts for its calls are sent (optional)"},"purpose":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Purpose"},"requestedScopes":{"anyOf":[{"items":{"type":"string","enum":["calls:book_approved","calls:book_new","calls:coach","calls:transfer","calls:hangup","calls:listen","calls:vault"]},"type":"array","minItems":1},{"type":"null"}],"title":"Requestedscopes","description":"Permissions the agent asks for. Required for new_account, new_token and update_permissions"},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Note","description":"Personal wording from the agent, shown in the email and on the approval page"},"temporary":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Temporary","description":"Ask for a temporary token (new_account / new_token). Default lifetime 24 hours; set validForHours to choose."},"validForHours":{"anyOf":[{"type":"integer","maximum":168.0,"minimum":1.0},{"type":"null"}],"title":"Validforhours","description":"Temporary token lifetime in whole hours after the person approves, 1 to 168 (one week). Implies temporary. Ask again as often as you need; each approval is one tap."}},"type":"object","required":["email","name"],"title":"AccessRequestBody"},"AccessRequestView":{"properties":{"id":{"type":"string","title":"Id"},"action":{"type":"string","enum":["new_account","new_token","rotate_token","update_permissions","remove_tokens"],"title":"Action"},"status":{"type":"string","enum":["PENDING","APPROVED","DECLINED","EXPIRED"],"title":"Status"},"email":{"type":"string","title":"Email"},"agentName":{"type":"string","title":"Agentname"},"agentEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agentemail"},"tokenId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tokenid"},"tokenIds":{"items":{"type":"string"},"type":"array","title":"Tokenids"},"requestedScopes":{"items":{"type":"string"},"type":"array","title":"Requestedscopes"},"grantedScopes":{"items":{"type":"string"},"type":"array","title":"Grantedscopes"},"createdAt":{"type":"string","title":"Createdat"},"expiresAt":{"type":"string","title":"Expiresat"},"approvedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Approvedat"},"temporary":{"type":"boolean","title":"Temporary","description":"Temporary token: stops on its own validForHours after approval"},"validForHours":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Validforhours"},"tokenExpiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tokenexpiresat","description":"Once active: when a temporary token stops"},"apiKey":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Apikey","description":"The token, shown once at creation. Inert (403 token_pending_approval) until the person approves."},"tokenStatus":{"anyOf":[{"type":"string","enum":["PENDING","ACTIVE","REVOKED"]},{"type":"null"}],"title":"Tokenstatus"},"pollSecret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pollsecret","description":"Shown once"},"pollUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pollurl","description":"Shown once; poll it every 30 to 60 s"}},"type":"object","required":["id","action","status","email","agentName","tokenId","tokenIds","requestedScopes","grantedScopes","createdAt","expiresAt","approvedAt","temporary","validForHours","tokenExpiresAt"],"title":"AccessRequestView"},"AnswerAccepted":{"properties":{"questionId":{"type":"string","title":"Questionid"},"state":{"type":"string","const":"ANSWERED","title":"State"},"answeredBy":{"type":"string","title":"Answeredby"},"noteId":{"type":"string","title":"Noteid"}},"type":"object","required":["questionId","state","answeredBy","noteId"],"title":"AnswerAccepted"},"AssistantLine":{"properties":{"state":{"type":"string","const":"ADDED","title":"State"},"at":{"type":"string","title":"At"},"seq":{"type":"integer","title":"Seq"}},"type":"object","required":["state","at","seq"],"title":"AssistantLine"},"AssistantLineView":{"properties":{"by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"By","description":"The seat that wrote it"},"text":{"type":"string","title":"Text"},"doing":{"type":"boolean","title":"Doing","description":"What it was doing then; false: what it found","default":false},"texted":{"type":"boolean","title":"Texted","description":"It was also texted to the person","default":false},"at":{"type":"string","title":"At"}},"type":"object","required":["text","at"],"title":"AssistantLineView"},"CallAnswerRequest":{"properties":{"text":{"type":"string","maxLength":1000,"minLength":1,"title":"Text","description":"The answer, plain; the agent relays it exactly"},"questionId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$"},{"type":"null"}],"title":"Questionid","description":"Default: the latest open question"}},"type":"object","required":["text"],"title":"CallAnswerRequest","description":"call_answer: answer the phone agent's ask_for_help question (the first answer wins: you, or the person by text or on the call page)."},"CallAssistantRequest":{"properties":{"text":{"type":"string","maxLength":1000,"minLength":1,"title":"Text"},"doing":{"type":"boolean","title":"Doing","description":"true: what you are doing now (\"Looking up the drive from Madison to Decatur\"); false: what you found","default":false}},"type":"object","required":["text"],"title":"CallAssistantRequest","description":"call_assistant: the seat's own line in the call's transcript (never spoken)."},"CallBookRequest":{"properties":{"recipient":{"type":"string","title":"Recipient","description":"Who to call, E.164 (+12565550123). Needs calls:book_new unless the number is an approved contact (calls:book_approved)."},"who":{"type":"string","maxLength":200,"minLength":1,"title":"Who","description":"Who the recipient is, e.g. 'Dryden, adjuster at Allstate'"},"goal":{"type":"string","maxLength":1000,"minLength":1,"title":"Goal","description":"What the call is for, in one or two sentences"},"details":{"items":{"type":"string","maxLength":500,"minLength":1},"type":"array","maxItems":30,"title":"Details","description":"Shareable details: the information the agent is calling with (claim number, prescriptions and quantities, addresses). On a call for the person themself it says what is about them (name, numbers, address, date of birth) only when the other side needs it; leave out what the call does not need, such as their name for a stock check, and add no callback number unless the goal needs a callback"},"history":{"items":{"type":"string","maxLength":500,"minLength":1},"type":"array","maxItems":20,"title":"History","description":"Private history for the agent's judgment only, never voiced or hinted at (\"they pushed back on X last time; if they do, offer Y\"). Acted on only once the other side raises the subject"},"playbooks":{"items":{"type":"string","maxLength":1500,"minLength":1},"type":"array","maxItems":5,"title":"Playbooks","description":"Private how-to-handle-this-call guidance (tone, approach). Describe the intent; never give lines to say, the agent copies them word for word"},"smallTalk":{"items":{"type":"string","maxLength":200,"minLength":1},"type":"array","maxItems":6,"title":"Smalltalk","description":"Small-talk topics for lulls: ids from GET /api/v1/small-talk/topics or your own topic. Empty: a few are picked to fit the day"},"facts":{"items":{"type":"string","maxLength":500,"minLength":1},"type":"array","maxItems":30,"title":"Facts","description":"Same as details (kept for older clients)"},"mayShare":{"items":{"type":"string","maxLength":500,"minLength":1},"type":"array","maxItems":30,"title":"Mayshare","description":"Same as details (kept for older clients)"},"neverShare":{"items":{"type":"string","maxLength":500,"minLength":1},"type":"array","maxItems":30,"title":"Nevershare","description":"Hard limits: things it must never say, whatever is asked"},"collect":{"anyOf":[{"additionalProperties":{"type":"string","maxLength":300},"propertyNames":{"maxLength":60,"minLength":1},"type":"object"},{"type":"null"}],"title":"Collect","description":"What to find out: field name -> what to ask (at most 20). The transcript carries the answers; AI Call does not summarize."},"successCriteria":{"type":"string","maxLength":1000,"title":"Successcriteria","description":"When the call has done its job","default":""},"openingLine":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Openingline","description":"First sentence the agent says (optional)"},"goalMode":{"type":"boolean","title":"Goalmode","description":"On: the goal is the outcome the call must produce, and the agent pushes toward it tactfully with everything it has (rapport, what stands between them and yes, objections answered from the file or a lookup, trial closes, locking in amount/date/method/who). Off: it collects what the goal asks for without pushing for commitments","default":false},"agentName":{"anyOf":[{"type":"string","maxLength":40,"minLength":1},{"type":"null"}],"title":"Agentname","description":"The name the phone agent goes by on this call: the name you, the assistant booking it, go by (never a model or product name such as Claude, GPT or Codex). Default: your own persona's name (call_persona_save), else your token's name if it is a usable first name. The voice is matched to the name (a woman's name never gets a man's voice)"},"agentRole":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Agentrole","description":"Who it is on this call, e.g. 'the office coordinator at Northside Plumbing'; with it the agent speaks as that team"},"company":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Company","description":"The business this call is for; with it the agent speaks as that team and never names the person. Nothing is fixed on the account: you say it per call, or a saved profile piece does"},"rules":{"items":{"type":"string","maxLength":500,"minLength":1},"type":"array","maxItems":15,"title":"Rules","description":"How to be on this kind of call: the house rules of a side of life (a profile sets them: errands with the public, friends, family, a business), e.g. what stays private, how familiar to be, what it never promises"},"persona":{"type":"string","maxLength":3000,"title":"Persona","description":"Who your phone agent is as a person: a few sentences of background, quirks, how they talk, a bit of personal history and local ties (see call_guide for a sample to adapt). It plays the character, never recites it; if asked whether it is an AI it still says yes","default":""},"scene":{"type":"string","maxLength":1500,"title":"Scene","description":"The vibe and local color for this call: where and when it is, what people around there are talking about, the mood to set, how to connect before getting to business (see call_guide)","default":""},"vibe":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Vibe","description":"How it should come across: 'energetic and kind', 'compassionate and upbeat', 'relaxed and chill', 'persistent and kind', 'dismissive and forward'"},"voiceModel":{"anyOf":[{"type":"string","enum":["grok","qwen","gpt"]},{"type":"null"}],"title":"Voicemodel","description":"The model that is the voice on the phone: grok (default), qwen (Qwen 3.8 Omni: replies start a little later, and it needs more steering from the seat) or gpt (GPT-Live 1: full duplex, its tools run on a backend model). Else your persona's, else the account's"},"voice":{"anyOf":[{"type":"string","pattern":"^(?:[a-z][a-z0-9_-]{1,30}|voice_[A-Za-z0-9]{1,64})$"},{"type":"null"}],"title":"Voice","description":"xAI voice id. Male: altair, atlas, castor, cosmo, helios, helix, kepler, leo, lumen, lux, naksh, orion, perseus, rex, rigel, sal, sirius, zagan, zenith. Female: ara, aurora, carina, celeste, eve, iris, liora, luna, ursa. On GPT-Live also its own voices (marin, cedar...) or the id of one of the account's own (voice_...). Default: the account's voice"},"helpPolicy":{"type":"string","enum":["both","seat_first","seat_only"],"title":"Helppolicy","description":"Who gets the phone agent's ask_for_help questions: both (default: you through call_wait/call_answer and the person by text, at the same moment; the first answer wins and the other side is told), seat_first (the person is texted only if you have not answered within ownerFallbackSeconds), seat_only (never text the person)","default":"both"},"ownerFallbackSeconds":{"type":"integer","maximum":120.0,"minimum":5.0,"title":"Ownerfallbackseconds","description":"seat_first: seconds before the person is texted the question","default":25},"maxMinutes":{"type":"integer","maximum":120.0,"minimum":1.0,"title":"Maxminutes","description":"Hard limit for the call length in minutes (1 to 120, default 15)","default":15},"scheduledAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scheduledat","description":"Book it for later: when to dial, ISO 8601 with a UTC offset (2026-11-02T15:00:00-06:00 or ...Z), 1 minute to 30 days ahead, inside the person's allowed hours. Leave out to dial now"},"wakeLeadSeconds":{"type":"integer","maximum":3600.0,"minimum":30.0,"title":"Wakeleadseconds","description":"Scheduled calls: how long before scheduledAt to wake you (the call.wake webhook and wakeAt in the response, for your own cron)","default":120},"requireSeat":{"type":"boolean","title":"Requireseat","description":"Scheduled calls: dial only once you are in the seat (you called call_wait for this booking after wakeAt). Not there within seatGraceMinutes: the call is cancelled and the person is told","default":false},"seatGraceMinutes":{"type":"integer","maximum":60.0,"minimum":1.0,"title":"Seatgraceminutes","description":"requireSeat: how long past scheduledAt to wait for you","default":10},"context":{"anyOf":[{"type":"string","enum":["business","personal"]},{"type":"null"}],"title":"Context","description":"personal: a call for the person themself (checking on a friend, family, an errand): with a business it asks like any customer and names the person, or gives anything about them, only when the call needs it (a pharmacy looking up their prescription); a friend or family member hears who it is from. business: for a company; it speaks as the team. Default: business when the booking gives a company or agentRole, else on the person's behalf"},"vault":{"items":{"type":"string","maxLength":60,"minLength":1},"type":"array","maxItems":20,"title":"Vault","description":"Items from the person's vault this call may use, by name (alt ID; call_vault lists them). The voice agent gets a value only when it needs it, after the person approves when the item says ask first; you never see the values, and records show **ALT_ID:<name>** in place of any value the person keeps out of transcripts"},"payment":{"anyOf":[{"$ref":"#/components/schemas/Payment"},{"type":"null"}],"description":"Let it pay by card over the phone: {allowed, maxAmount}. When they are ready to take payment it asks for the card (a payment event, the call.payment webhook, a text to the person); send it with call_card then, never before"},"handoff":{"anyOf":[{"$ref":"#/components/schemas/Handoff"},{"type":"null"}],"description":"Pickup transfer: the call exists to get someone on the line for the person, then hand it to them. {to, when reached|live_person, reach, mode warm|cold}. Needs calls in LiveKit rooms"},"voicemail":{"anyOf":[{"type":"string","enum":["message","hangup","transfer"]},{"type":"null"}],"title":"Voicemail","description":"If it reaches voicemail: message (it waits for the tone and leaves a short message: who, what it is about, the callback number; then hangs up), hangup, or transfer (it rings the person, or the handoff target, so they leave the message themself; it says nothing). Default: transfer for a handoff call, message for a call for a business, hangup for a call on the person's own behalf (it leaves neither their name nor a number behind unless you ask for a message)"},"callbackNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Callbacknumber","description":"The number a voicemail message asks them to call back (default: the number the call comes from)"},"seatBrief":{"type":"string","maxLength":4000,"title":"Seatbrief","description":"A note to your future self for when you wake (why this call, what to watch for, what to do after). Never told to the voice agent; returned by call_upcoming and the call.wake webhook","default":""},"rolePlay":{"type":"boolean","title":"Roleplay","description":"A practice call: someone plays the other side. Its caller memory is kept apart: it builds on earlier practice calls only, and never shows up in (or reads from) the memory of real calls. Default false: every call is real, calls to the person's own phone included","default":false},"idempotencyKey":{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$","title":"Idempotencykey","description":"Required. Same key + same body returns the first booking; never dials twice. 8 to 200 of A-Z a-z 0-9 . _ : -"}},"type":"object","required":["recipient","who","goal","idempotencyKey"],"title":"CallBookRequest","description":"call_book: book an outbound call. The briefing is what the phone agent knows; it is frozen at dial time."},"CallBooking":{"properties":{"bookingId":{"type":"string","title":"Bookingid","description":"Use it with every other call tool"},"state":{"type":"string","enum":["SCHEDULED","QUEUED","DIALING","RINGING","CONNECTED","WRAPPING","ENDED","FAILED","CANCELLED","UNCERTAIN"],"title":"State"},"recipient":{"type":"string","title":"Recipient"},"who":{"type":"string","title":"Who"},"maxMinutes":{"type":"integer","title":"Maxminutes"},"callLink":{"type":"string","title":"Calllink","description":"https://aicall.prodevgroup.com/call/<token>: live transcript, notes, transfer, hang up, listen; read-only for 30 days after the call"},"createdAt":{"type":"string","title":"Createdat"},"note":{"type":"string","title":"Note","description":"Plain words for the human, e.g. \"Dialing now.\""},"scheduledAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scheduledat","description":"When it dials (scheduled calls)"},"wakeAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wakeat","description":"When to be back in the seat: set your own cron or wake-up for this time (the call.wake webhook fires then too)"},"requireSeat":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Requireseat"},"wakePrompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wakeprompt","description":"A ready-made prompt for your own scheduled wake-up (cron, scheduled task)"}},"type":"object","required":["bookingId","state","recipient","who","maxMinutes","callLink","createdAt","note"],"title":"CallBooking"},"CallDialRequest":{"properties":{"number":{"type":"string","title":"Number","description":"E.164 to ring into the call (an approved contact, or calls:book_new)"},"who":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Who","description":"Who that is, for the call page"},"commandId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$"},{"type":"null"}],"title":"Commandid","description":"Idempotency key"}},"type":"object","required":["number"],"title":"CallDialRequest","description":"call_dial: on a call_me call, ring someone into it."},"CallEvent":{"properties":{"seq":{"type":"integer","title":"Seq","description":"Durable, increasing; pass the last one back as after"},"at":{"type":"string","title":"At","description":"When AI Call recorded it (ISO 8601)"},"sourceAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourceat"},"callId":{"type":"string","title":"Callid"},"bookingId":{"type":"string","title":"Bookingid"},"kind":{"type":"string","enum":["state","transcript","agent_state","note","question","text","control","proposal","relay","assistant","payment","vault"],"title":"Kind"},"data":{"additionalProperties":true,"type":"object","title":"Data","description":"state: {state, outcome?}; transcript: {speaker caller|agent|owner|transfer:<number>, itemId, text, final, settled}; agent_state: {state listening|speaking}; note: {noteId, source, author, kind, mode, text, state}; question: {questionId, text, state OPEN|ANSWERED|TIMED_OUT, answer?, answeredBy?} (answer it with call_answer); text: {direction out|in, address, body, state}; control: {action, mode, actor}; proposal: {proposalId, to, body, state PENDING|SENT|DECLINED|EXPIRED|FAILED|REVISE} (the agent asked to text them; the person approves)"}},"type":"object","required":["seq","at","callId","bookingId","kind","data"],"title":"CallEvent"},"CallEvents":{"properties":{"bookingId":{"type":"string","title":"Bookingid"},"events":{"items":{"$ref":"#/components/schemas/CallEvent"},"type":"array","title":"Events"},"cursor":{"type":"integer","title":"Cursor","description":"Pass back as after"},"state":{"type":"string","enum":["SCHEDULED","QUEUED","DIALING","RINGING","CONNECTED","WRAPPING","ENDED","FAILED","CANCELLED","UNCERTAIN"],"title":"State"},"more":{"type":"boolean","title":"More","description":"true: more events are ready, call again at once"},"callLink":{"type":"string","title":"Calllink"},"caller":{"anyOf":[{"$ref":"#/components/schemas/CallerView"},{"type":"null"}],"description":"Who called in (only on a call that came in): read their memory with call_memory"},"voiceModel":{"anyOf":[{"type":"string","enum":["grok","qwen","gpt"]},{"type":"null"}],"title":"Voicemodel","description":"The model that is the voice on this call, once it is on: qwen needs more nudging, gpt hears your notes while it talks (call guide section 5)"},"result":{"anyOf":[{"$ref":"#/components/schemas/CallResult"},{"type":"null"}],"description":"Present on the last call_wait after the call ended"}},"type":"object","required":["bookingId","events","cursor","state","more","callLink"],"title":"CallEvents"},"CallFileItem":{"properties":{"fileId":{"type":"string","title":"Fileid"},"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type"},"size":{"type":"integer","title":"Size"},"url":{"type":"string","title":"Url","description":"GET it with your own key"},"at":{"type":"string","title":"At"},"secondsIntoCall":{"type":"integer","title":"Secondsintocall"},"source":{"type":"string","enum":["camera","page"],"title":"Source","description":"camera: a frame or photo from the camera link; page: sent from the call page"}},"type":"object","required":["fileId","name","type","size","url","at","secondsIntoCall","source"],"title":"CallFileItem"},"CallFiles":{"properties":{"files":{"items":{"$ref":"#/components/schemas/CallFileItem"},"type":"array","title":"Files"}},"type":"object","required":["files"],"title":"CallFiles","description":"call_files: the call's newest photos, files and camera frames, oldest of them first."},"CallHangupRequest":{"properties":{"mode":{"type":"string","enum":["soft","hard"],"title":"Mode","description":"soft: the agent says goodbye in one sentence, the line drops after at most 45 s; hard: drop now","default":"soft"},"reason":{"type":"string","maxLength":500,"minLength":1,"title":"Reason","description":"Why; kept with the call record"},"commandId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$"},{"type":"null"}],"title":"Commandid","description":"Idempotency key"}},"type":"object","required":["reason"],"title":"CallHangupRequest","description":"call_hangup: end the call."},"CallHoldRequest":{"properties":{"tellThem":{"anyOf":[{"type":"string","maxLength":300,"minLength":1},{"type":"null"}],"title":"Tellthem","description":"What it tells them when a live person comes back, before bringing the person back (default: one moment, it is grabbing them)"},"commandId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$"},{"type":"null"}],"title":"Commandid","description":"Idempotency key"}},"type":"object","title":"CallHoldRequest","description":"call_hold: on a call_me call, the voice agent takes over a hold."},"CallLinkView":{"properties":{"bookingId":{"type":"string","title":"Bookingid"},"url":{"type":"string","title":"Url"},"expiresAt":{"type":"string","title":"Expiresat","description":"Live during the call, then a read-only page for 30 days"}},"type":"object","required":["bookingId","url","expiresAt"],"title":"CallLinkView"},"CallMe":{"properties":{"dial":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dial"},"agent":{"type":"string","enum":["off","muted","on"],"title":"Agent","default":"off"},"callerId":{"type":"string","enum":["mine","aicall"],"title":"Callerid","default":"mine"}},"type":"object","title":"CallMe","description":"A call the person places themself (call_me): stored on the booking."},"CallMeRequest":{"properties":{"dial":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dial","description":"E.164 to connect them to as soon as they pick up (an approved contact, or calls:book_new). Leave out and they dial from their keypad (the number, then #), or you dial later with call_dial"},"who":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Who","description":"Who they are calling, e.g. 'Home Depot pro desk' (for the call page and the transcript)"},"about":{"type":"string","maxLength":1000,"title":"About","description":"What the call is about: what the voice agent works from if it is asked to help","default":""},"details":{"items":{"type":"string","maxLength":500,"minLength":1},"type":"array","maxItems":30,"title":"Details","description":"What the voice agent may share if it helps (account or claim numbers, a PIN for a phone menu)"},"agent":{"type":"string","enum":["off","muted"],"title":"Agent","description":"The voice agent. off: not on the line until it is needed (** or *8 on their keypad, call_hold, call_mute false, or a text from them). muted: on the line from the start, listening and saying nothing until unmuted or messaged","default":"off"},"callerId":{"type":"string","enum":["mine","aicall"],"title":"Callerid","description":"What the people they call see: mine (their own cell, once it is verified with the carrier; until then AI Call's number) or aicall. The call to them always comes from AI Call's number","default":"mine"},"agentName":{"anyOf":[{"type":"string","maxLength":40,"minLength":1},{"type":"null"}],"title":"Agentname","description":"The name the voice agent goes by if it speaks (default: your persona's name)"},"company":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Company","description":"If the call is for a business, the business: the voice agent then speaks as that team"},"context":{"anyOf":[{"type":"string","enum":["business","personal"]},{"type":"null"}],"title":"Context","description":"As in call_book; default: on the person's behalf"},"maxMinutes":{"type":"integer","maximum":120.0,"minimum":1.0,"title":"Maxminutes","description":"Hard limit for the call length in minutes (1 to 120, default 60)","default":60},"scheduledAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scheduledat","description":"Ring them later instead of now (ISO 8601 with a UTC offset), as in call_book"},"idempotencyKey":{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$","title":"Idempotencykey","description":"Required. Same key + same body returns the first booking; never rings twice"}},"type":"object","required":["idempotencyKey"],"title":"CallMeRequest","description":"call_me (Sam, 2026-10-26): \"if I just wanted to call myself, but I wanted you to join me in the call I could say to\nyou give me a call and I pick up the line and then I call out to whoever I want to and the whole thing gets recorded\nand you're listening, watching the transcript in real time and completing tasks\"."},"CallMemory":{"properties":{"number":{"type":"string","title":"Number"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Who they are: the contact's label, else how the call was booked"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"The running summary of everything with them: who they are, claim and account numbers, what is still agreed, owed or open. Rewritten after each call; null before the first is written"},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updatedat","description":"When the running summary was last rewritten (ISO 8601)"},"calls":{"items":{"$ref":"#/components/schemas/MemoryCall"},"type":"array","title":"Calls","description":"Every call that number was on, newest first: each call's summary, never its transcript"},"matches":{"anyOf":[{"items":{"$ref":"#/components/schemas/MemoryMatch"},"type":"array"},{"type":"null"}],"title":"Matches","description":"Only from the MCP tool call_memory when it is given a query: the same list GET /memory/search returns, for that number"}},"type":"object","required":["number","label","summary","updatedAt","calls"],"title":"CallMemory"},"CallMemoryRead":{"properties":{"bookingId":{"type":"string","title":"Bookingid"},"number":{"type":"string","title":"Number","description":"Whose side of the call this is (a call that had several numbers on the line is kept once per number)"},"label":{"type":"string","title":"Label","description":"Who it was with: the contact's label, else the number"},"at":{"type":"string","title":"At","description":"When this number came on the line (ISO 8601)"},"part":{"type":"string","enum":["summary","transcript"],"title":"Part"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"part summary: gist, authorizations, agreements, issues, key details, next steps; null when none was written (see note)"},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript","description":"part transcript: only what was said while this number was on the line, one line per turn, filler left out"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note","description":"e.g. that no summary was written, so read the transcript"}},"type":"object","required":["bookingId","number","label","at","part"],"title":"CallMemoryRead"},"CallMuteRequest":{"properties":{"muted":{"type":"boolean","title":"Muted","description":"true: it keeps listening (and the call keeps being transcribed) but says nothing; false: it can speak again (on a call_me call this brings it onto the line)"},"commandId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$"},{"type":"null"}],"title":"Commandid","description":"Idempotency key"}},"type":"object","required":["muted"],"title":"CallMuteRequest","description":"call_mute: the voice agent listens and says nothing, or speaks again."},"CallNoteRequest":{"properties":{"text":{"type":"string","maxLength":1000,"minLength":1,"title":"Text"},"mode":{"type":"string","enum":["guidance","speak"],"title":"Mode","description":"guidance: worked in where it fits the conversation, never read aloud; speak: the agent says it at the next pause (after the other person finishes and its own audio has played out)","default":"guidance"},"kind":{"type":"string","enum":["detail","private"],"title":"Kind","description":"detail: information it may share; private: guidance for its judgment, never voiced. Mid-call notes should say what to change from now on, not a line to say","default":"detail"},"supersedes":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9_-]{1,80}$"},{"type":"null"}],"title":"Supersedes","description":"noteId of an earlier note not yet delivered; it is dropped"},"commandId":{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$","title":"Commandid","description":"Required. Idempotency key for this note (8 to 200 of A-Z a-z 0-9 . _ : -)"}},"type":"object","required":["text","commandId"],"title":"CallNoteRequest","description":"call_note: a note to the phone agent during the call."},"CallResult":{"properties":{"bookingId":{"type":"string","title":"Bookingid"},"state":{"type":"string","enum":["SCHEDULED","QUEUED","DIALING","RINGING","CONNECTED","WRAPPING","ENDED","FAILED","CANCELLED","UNCERTAIN"],"title":"State"},"outcome":{"anyOf":[{"type":"string","enum":["answered","no_answer","busy","failed","canceled"]},{"type":"null"}],"title":"Outcome"},"hungUpBy":{"anyOf":[{"type":"string","enum":["caller","agent","coach","owner","timeout","unknown"]},{"type":"null"}],"title":"Hungupby"},"recipient":{"type":"string","title":"Recipient"},"who":{"type":"string","title":"Who","default":""},"callerId":{"type":"string","title":"Callerid","default":""},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Startedat"},"answeredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answeredat"},"endedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endedat"},"durationSeconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Durationseconds"},"notes":{"items":{"$ref":"#/components/schemas/NoteView"},"type":"array","title":"Notes"},"questions":{"items":{"$ref":"#/components/schemas/QuestionView"},"type":"array","title":"Questions"},"passedAlong":{"items":{"$ref":"#/components/schemas/PassedAlongView"},"type":"array","title":"Passedalong","description":"Instructions and feedback the agent passed to the team during the call (relay events)"},"assistant":{"items":{"$ref":"#/components/schemas/AssistantLineView"},"type":"array","title":"Assistant","description":"The seat's own lines (call_assistant, call_text_owner): what it did and found, never spoken"},"texts":{"items":{"$ref":"#/components/schemas/TextView"},"type":"array","title":"Texts"},"proposals":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Proposals","description":"Texts the agent asked to send to the other side: {proposalId, to, body, state SENT|DECLINED|EXPIRED|FAILED, decidedBy}"},"transcript":{"items":{"$ref":"#/components/schemas/TranscriptLine"},"type":"array","title":"Transcript"},"callLink":{"type":"string","title":"Calllink"},"recording":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Recording","description":"{url, seconds}: the call's audio (MP3) when the person records calls; kept 30 days. The url needs calls:listen"},"minutes":{"$ref":"#/components/schemas/Minutes","description":"Billable minutes by leg {callee, transfer, agent}, each rounded up to a whole minute. All 0 for a call that was never answered, and until the call has ended"},"line":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Line","description":"{theirAudioLostPercent, choppy, note}: how much of the other side's audio reached AI Call; choppy at 5% or more (their phone line or the route to it, not the agent). Calls in LiveKit rooms only; null when not measured"}},"type":"object","required":["bookingId","state","outcome","hungUpBy","recipient","startedAt","answeredAt","endedAt","durationSeconds","notes","transcript","callLink","minutes"],"title":"CallResult"},"CallSeatAwayRequest":{"properties":{"reason":{"type":"string","maxLength":300,"minLength":1,"title":"Reason","description":"What you are stepping out to do, e.g. handing the Carson claim to the Legal Bot (your next run reads it here)"}},"type":"object","required":["reason"],"title":"CallSeatAwayRequest"},"CallTextOwnerRequest":{"properties":{"body":{"type":"string","maxLength":600,"minLength":1,"title":"Body"}},"type":"object","required":["body"],"title":"CallTextOwnerRequest","description":"call_text_owner: a text to the person, from their text line."},"CallTransferRequest":{"properties":{"target":{"type":"string","title":"Target","description":"\"owner\" (the person who approved your token) or an E.164 number"},"mode":{"type":"string","enum":["soft","instant"],"title":"Mode","description":"soft (warm): the agent tells them to hold a moment (the hold line), hold music plays while the target rings, and when the target picks up the agent briefs them privately before connecting; instant (cold): hold music at once, connected on the answer. If nobody answers within 25 s the agent comes back, promises a callback and carries on","default":"soft"},"holdLine":{"anyOf":[{"type":"string","maxLength":300,"minLength":1},{"type":"null"}],"title":"Holdline","description":"soft only; said word for word. Default: \"Hey, my boss is free now and will take over from here. Please hold.\" on a business call (the agent speaks as a persona), the person's first name instead of \"my boss\" on a personal one, \"someone from our team\" for a number other than the person's"},"commandId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$"},{"type":"null"}],"title":"Commandid","description":"Idempotency key; send one so a retry never transfers twice"}},"type":"object","required":["target"],"title":"CallTransferRequest","description":"call_transfer: hand the live call to the person (owner) or to a number."},"CallVoiceRequest":{"properties":{"voice":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Voice","description":"xAI voice id, or a Qwen voice name on Qwen, or a GPT-Live voice on GPT-Live (one of its own, or voice_... for one of the account's own); it speaks in it from its next sentence (GPT-Live: a moment later, in a fresh session). The booking and profile keep theirs"},"voiceModel":{"anyOf":[{"type":"string","enum":["grok","qwen","gpt"]},{"type":"null"}],"title":"Voicemodel","description":"Move the call to this engine (for comparing voices): it picks up a second or two later with the call so far in writing. voice, if given, is its voice there"},"commandId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,200}$"},{"type":"null"}],"title":"Commandid","description":"Idempotency key"}},"type":"object","title":"CallVoiceRequest","description":"call_voice: the voice agent switches to another voice, or to the other engine, on the live call."},"CallerView":{"properties":{"number":{"type":"string","title":"Number","description":"The caller's number: pass it to call_memory"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Their name when AI Call knows it (the person themself, a saved contact or caller memory)"}},"type":"object","required":["number"],"title":"CallerView"},"CardRequest":{"properties":{"number":{"type":"string","maxLength":23,"minLength":12,"title":"Number","description":"Card number (spaces or dashes are fine)"},"exp":{"type":"string","maxLength":7,"minLength":4,"title":"Exp","description":"Expiration, MM/YY"},"cvc":{"type":"string","pattern":"^[0-9]{3,4}$","title":"Cvc","description":"Security code"},"zip":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Zip","description":"Billing ZIP, if they ask"},"name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Name","description":"Name on the card, if they ask"}},"type":"object","required":["number","exp","cvc"],"title":"CardRequest","description":"call_card: the card for a payment the voice agent asked for. Held in memory for that payment only: never stored,\nlogged, recorded or shown again."},"ChangeRequestBody":{"properties":{"requestedScopes":{"items":{"type":"string","enum":["calls:book_approved","calls:book_new","calls:coach","calls:transfer","calls:hangup","calls:listen","calls:vault"]},"type":"array","minItems":1,"title":"Requestedscopes","description":"The permissions you want from now on"},"purpose":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Purpose"},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Note"},"agentName":{"anyOf":[{"type":"string","maxLength":80,"minLength":2},{"type":"null"}],"title":"Agentname"}},"type":"object","required":["requestedScopes"],"title":"ChangeRequestBody"},"ControlAccepted":{"properties":{"commandId":{"type":"string","title":"Commandid"},"state":{"type":"string","const":"QUEUED","title":"State"},"action":{"type":"string","enum":["transfer","hangup","mute","dial","hold","voice","model"],"title":"Action"},"mode":{"type":"string","title":"Mode"},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target"},"graceSeconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Graceseconds","description":"hangup soft: seconds before the line drops (45)"}},"type":"object","required":["commandId","state","action","mode"],"title":"ControlAccepted"},"FromTemplate":{"properties":{"template":{"anyOf":[{"type":"string","maxLength":48,"minLength":2},{"type":"null"}],"title":"Template","description":"One template name from call_templates"},"use":{"anyOf":[{"items":{"type":"string","maxLength":48,"minLength":2},"type":"array","maxItems":6},{"type":"null"}],"title":"Use","description":"Several templates mashed together, in order (lists add up, objects merge, later single values win): e.g. a profile, a persona, a scene and a kind of call"},"fill":{"additionalProperties":true,"type":"object","title":"Fill","description":"Blank name to value (a list for list blanks)"},"booking":{"additionalProperties":true,"type":"object","title":"Booking","description":"call_book fields on top: recipient and idempotencyKey at least; any other field overrides the template"}},"type":"object","required":["booking"],"title":"FromTemplate"},"Handoff":{"properties":{"to":{"type":"string","title":"To","description":"Who takes the call: \"owner\" (the person, on their phone) or an E.164 number on their approved list","default":"owner"},"when":{"type":"string","enum":["reached","live_person"],"title":"When","description":"reached: the agent gets the person named in reach on the line (front desk, phone menu), tells them someone is free to take it, then hands it over. live_person: the agent says nothing while it holds and works the phone menu; the moment a live person answers it says one moment and hands it over","default":"reached"},"reach":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Reach","description":"reached: who to get on the line, e.g. 'John at City Lumber' (default: who)"},"mode":{"anyOf":[{"type":"string","enum":["warm","cold"]},{"type":"null"}],"title":"Mode","description":"warm: whoever takes it is briefed privately first; cold: connected at once. Default warm for reached, cold for live_person (a live agent on a hold line will not wait)"}},"type":"object","title":"Handoff","description":"Pickup transfer (Sam, 2026-10-26): \"Get me on the phone with John at City Lumber\" (reach) or \"wait on hold with\nthe IRS and give the call to me as soon as they answer\" (hold)."},"MeView":{"properties":{"user":{"additionalProperties":true,"type":"object","title":"User","description":"{id, email, name}: the person the token acts for"},"key":{"additionalProperties":true,"type":"object","title":"Key","description":"{id, name, agentName, agentEmail, prefix, scopes, engines, outboundOnly, createdAt, expiresAt, lastUsedAt}: engines are the voiceModel values this token may use"},"settings":{"additionalProperties":true,"type":"object","title":"Settings","description":"{notifyOnCall, allowedHours, allowedHoursText}"}},"type":"object","required":["user","key","settings"],"title":"MeView"},"MemoryCall":{"properties":{"bookingId":{"type":"string","title":"Bookingid","description":"Open it with call_memory_read"},"at":{"type":"string","title":"At","description":"When this number came on the line (ISO 8601)"},"minutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Minutes","description":"How long they were on the line, in minutes; null while the call is still going"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome","description":"How the call ended: answered, no_answer, busy, failed, canceled"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"Gist, authorizations, agreements, issues, key details and next steps; null until it is written (a call that just ended)"}},"type":"object","required":["bookingId","at","minutes","outcome","summary"],"title":"MemoryCall"},"MemoryMatch":{"properties":{"bookingId":{"type":"string","title":"Bookingid","description":"Open it with call_memory_read"},"number":{"type":"string","title":"Number"},"label":{"type":"string","title":"Label","description":"Who it was with: the contact's label, else the number"},"at":{"type":"string","title":"At","description":"When this number came on the line (ISO 8601)"},"said":{"type":"string","title":"Said","description":"The words that matched, with a little around them"}},"type":"object","required":["bookingId","number","label","at","said"],"title":"MemoryMatch"},"MemorySearch":{"properties":{"matches":{"items":{"$ref":"#/components/schemas/MemoryMatch"},"type":"array","title":"Matches","description":"The earlier calls that best match the words, best first (at most 5)"}},"type":"object","required":["matches"],"title":"MemorySearch"},"Minutes":{"properties":{"callee":{"type":"integer","title":"Callee","description":"The line to the person called: answered to ended, rounded up"},"transfer":{"type":"integer","title":"Transfer","description":"The transfer target on the line: from the moment it connected to the end, rounded up; 0 when the call was not transferred"},"agent":{"type":"integer","title":"Agent","description":"The voice agent on the line: answered to the handover (or to the end without a transfer), rounded up"}},"type":"object","required":["callee","transfer","agent"],"title":"Minutes","description":"Billable minutes by leg. Each leg of each call is rounded up to a whole minute (carrier style); see src/aicall/usage.py."},"NoteQueued":{"properties":{"noteId":{"type":"string","title":"Noteid"},"state":{"type":"string","enum":["QUEUED","HELD"],"title":"State","description":"HELD until the call is answered"},"mode":{"type":"string","enum":["guidance","speak"],"title":"Mode"},"queuedAt":{"type":"string","title":"Queuedat"}},"type":"object","required":["noteId","state","mode","queuedAt"],"title":"NoteQueued"},"NoteView":{"properties":{"noteId":{"type":"string","title":"Noteid"},"source":{"type":"string","enum":["owner","coach","owner_text","answer","system"],"title":"Source","description":"owner: the person on the call page; coach: an agent (call_note); owner_text: the person's text to the line; answer: a reply to the agent's ask_for_help; system: AI Call itself (wrap-up, timeouts)"},"author":{"type":"string","title":"Author"},"kind":{"type":"string","title":"Kind","default":"detail"},"mode":{"type":"string","enum":["guidance","speak"],"title":"Mode"},"text":{"type":"string","title":"Text"},"state":{"type":"string","enum":["HELD","QUEUED","APPLIED","RESPONSE_REQUESTED","STALE","FAILED","UNCERTAIN"],"title":"State"},"queuedAt":{"type":"string","title":"Queuedat"},"releasedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Releasedat"},"appliedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Appliedat"}},"type":"object","required":["noteId","source","author","mode","text","state","queuedAt"],"title":"NoteView"},"OwnerText":{"properties":{"state":{"type":"string","const":"QUEUED","title":"State"},"at":{"type":"string","title":"At"}},"type":"object","required":["state","at"],"title":"OwnerText"},"PassedAlongView":{"properties":{"text":{"type":"string","title":"Text","description":"What the person on the call wanted the team to know or do, as the agent passed it along"},"at":{"type":"string","title":"At"},"seatConnected":{"type":"boolean","title":"Seatconnected","description":"Whether an AI was in the seat (waiting on the call) to act on it then; false: nobody was, so it is a message for later","default":true},"trusted":{"type":"boolean","title":"Trusted","description":"Set by AI Call: everyone on the line then was the person on a verified line. Not trusted: information only","default":false}},"type":"object","required":["text","at"],"title":"PassedAlongView"},"Payment":{"properties":{"allowed":{"type":"boolean","title":"Allowed","description":"The agent may pay by card on this call","default":true},"maxAmount":{"anyOf":[{"type":"number","maximum":100000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Maxamount","description":"Most it may pay (in dollars); a higher total is checked with you first"},"approve":{"type":"string","enum":["text","none"],"title":"Approve","description":"text (default): before any card is sent the person gets \"Total to pay is $X at <who> - Card ending in 1111. Approve?\" with the items; YES releases the card, anything else goes back to the agent, which rechecks the order with them. none: no approval step","default":"text"},"cardLast4":{"anyOf":[{"type":"string","pattern":"^[0-9]{4}$"},{"type":"null"}],"title":"Cardlast4","description":"The card's last four digits, for the approval text (never the full number)"},"card":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,39}$"},{"type":"null"}],"title":"Card","description":"Which of the person's stored cards to use, by its vault name (e.g. amex). Only the name ever reaches AI Call; it is echoed in the payment event so the seat sends the right one"},"vaultCard":{"anyOf":[{"type":"string","maxLength":60,"minLength":1},{"type":"null"}],"title":"Vaultcard","description":"A card in the person's AI Call vault, by name (alt ID; call_vault lists cards with kind card). When they are ready to take payment (and the person approved the total, when totals are approved) AI Call hands it straight to the voice agent: nobody sends a card"}},"type":"object","title":"Payment","description":"Paying by card over the phone (Sam, 2026-10-26: \"places the order, and can pay over the phone ... I wouldn't send\nthe card information until they get to the point of needing it\")."},"QuestionView":{"properties":{"questionId":{"type":"string","title":"Questionid"},"text":{"type":"string","title":"Text"},"state":{"type":"string","enum":["OPEN","ANSWERED","TIMED_OUT"],"title":"State"},"askedAt":{"type":"string","title":"Askedat"},"answeredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answeredat"},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answeredby","description":"seat (call_answer), owner_text (a text reply), owner (the call page)"},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer"}},"type":"object","required":["questionId","text","state","askedAt"],"title":"QuestionView"},"SeatAway":{"properties":{"state":{"type":"string","const":"AWAY","title":"State"},"wakeUp":{"type":"string","const":"sent","title":"Wakeup"},"next":{"type":"string","title":"Next"}},"type":"object","required":["state","wakeUp","next"],"title":"SeatAway"},"SeatWakeupBody":{"properties":{"email":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"title":"Email","description":"Your own email address: a routine of yours that runs when mail arrives there is woken by an email whose subject and body carry the callId"},"url":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Url","description":"Or a public https webhook (a JSON POST of the call.seat event)"},"key":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Key","description":"With url: sent as Authorization: Bearer <key> (a Grok Bot routine's webhook key). Stored and never shown again"}},"type":"object","title":"SeatWakeupBody"},"TextView":{"properties":{"direction":{"type":"string","enum":["out","in"],"title":"Direction"},"address":{"type":"string","title":"Address"},"body":{"type":"string","title":"Body"},"state":{"type":"string","title":"State"},"at":{"type":"string","title":"At"}},"type":"object","required":["direction","address","body","state","at"],"title":"TextView"},"TranscriptLine":{"properties":{"speaker":{"type":"string","title":"Speaker","description":"caller | agent | owner | transfer:<number>"},"at":{"type":"string","title":"At"},"text":{"type":"string","title":"Text"},"interrupted":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Interrupted","description":"agent line the other side talked over: its end may not have been heard"}},"type":"object","required":["speaker","at","text"],"title":"TranscriptLine"},"UpcomingCall":{"properties":{"bookingId":{"type":"string","title":"Bookingid"},"state":{"type":"string","enum":["SCHEDULED","QUEUED","DIALING","RINGING","CONNECTED","WRAPPING","ENDED","FAILED","CANCELLED","UNCERTAIN"],"title":"State"},"recipient":{"type":"string","title":"Recipient"},"who":{"type":"string","title":"Who"},"goal":{"type":"string","title":"Goal"},"scheduledAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scheduledat"},"wakeAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wakeat"},"requireSeat":{"type":"boolean","title":"Requireseat"},"seatBrief":{"type":"string","title":"Seatbrief","description":"Your note to yourself from booking time"},"callLink":{"type":"string","title":"Calllink"}},"type":"object","required":["bookingId","state","recipient","who","goal","scheduledAt","wakeAt","requireSeat","seatBrief","callLink"],"title":"UpcomingCall"},"UpcomingCalls":{"properties":{"calls":{"items":{"$ref":"#/components/schemas/UpcomingCall"},"type":"array","title":"Calls","description":"This token's calls not finished yet (scheduled, queued or live), soonest first"}},"type":"object","required":["calls"],"title":"UpcomingCalls"},"UsageEngine":{"properties":{"calls":{"type":"integer","title":"Calls"},"minutes":{"$ref":"#/components/schemas/Minutes"}},"type":"object","required":["calls","minutes"],"title":"UsageEngine"},"UsageToken":{"properties":{"tokenId":{"type":"string","title":"Tokenid","description":"The token's ID (tok_...), never the token itself"},"agentName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agentname","description":"The agent name the token goes by (falls back to the token's name)"},"calls":{"type":"integer","title":"Calls"},"minutes":{"$ref":"#/components/schemas/Minutes"}},"type":"object","required":["tokenId","agentName","calls","minutes"],"title":"UsageToken"},"UsageView":{"properties":{"month":{"type":"string","title":"Month","description":"The UTC calendar month, YYYY-MM"},"from":{"type":"string","title":"From","description":"First instant of the month (ISO 8601, UTC)"},"to":{"type":"string","title":"To","description":"First instant of the next month (ISO 8601, UTC); the month ends just before it"},"calls":{"type":"integer","title":"Calls","description":"Answered calls that ended and were answered in this month"},"minutes":{"$ref":"#/components/schemas/Minutes","description":"The month's minutes across all of the person's tokens"},"byEngine":{"additionalProperties":{"$ref":"#/components/schemas/UsageEngine"},"propertyNames":{"enum":["bridge","livekit"]},"type":"object","title":"Byengine","description":"The same, split by call engine (bridge: Twilio Media Streams; livekit: LiveKit rooms). Calls from before the engine was recorded count as bridge"},"tokens":{"items":{"$ref":"#/components/schemas/UsageToken"},"type":"array","title":"Tokens","description":"Per token, most minutes first. Only tokens with a call in the month; removed tokens included"}},"type":"object","required":["month","from","to","calls","minutes","byEngine","tokens"],"title":"UsageView"},"WebhookBody":{"properties":{"url":{"type":"string","maxLength":2000,"minLength":10,"title":"Url","description":"https URL that receives JSON POSTs"},"events":{"items":{"type":"string","enum":["call.wake","call.connected","call.question","call.relay","call.payment","call.ended","call.seat"]},"type":"array","title":"Events","description":"Empty = all but call.seat"},"bearer":{"anyOf":[{"type":"string","maxLength":500,"minLength":8},{"type":"null"}],"title":"Bearer","description":"Sent as Authorization: Bearer <bearer> on every delivery, for a receiver that wants its own key (a Grok Bot routine's webhook key). Stored and never shown again."}},"type":"object","required":["url"],"title":"WebhookBody"},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"description":"Optional extra data about the error"}}}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Agent token (aic_live_...)"}}}}