diff --git a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-darwin-amd64.tar.gz b/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-darwin-amd64.tar.gz deleted file mode 100644 index e905fa3..0000000 Binary files a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-darwin-amd64.tar.gz and /dev/null differ diff --git a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-darwin-arm64.tar.gz b/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-darwin-arm64.tar.gz deleted file mode 100644 index 849eb9c..0000000 Binary files a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-darwin-arm64.tar.gz and /dev/null differ diff --git a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-linux-amd64.tar.gz b/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-linux-amd64.tar.gz deleted file mode 100644 index 0654135..0000000 Binary files a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-linux-amd64.tar.gz and /dev/null differ diff --git a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-linux-arm64.tar.gz b/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-linux-arm64.tar.gz deleted file mode 100644 index 4ce756d..0000000 Binary files a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-linux-arm64.tar.gz and /dev/null differ diff --git a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-windows-amd64.tar.gz b/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-windows-amd64.tar.gz deleted file mode 100644 index 82c6b80..0000000 Binary files a/submissions/io.pilot.agentphone/io.pilot.agentphone-0.1.0-windows-amd64.tar.gz and /dev/null differ diff --git a/submissions/io.pilot.agentphone/metadata.json b/submissions/io.pilot.agentphone/metadata.json deleted file mode 100644 index 287d4e0..0000000 --- a/submissions/io.pilot.agentphone/metadata.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "schema_version": 1, - "id": "io.pilot.agentphone", - "display_name": "AgentPhone", - "tagline": "A real phone number for your agent — calls, SMS, and conversations over REST", - "description_md": "Give your agent a real phone number: place and receive voice calls, send and receive SMS/iMessage, and hold threaded conversations — all over REST. Provision a number, create a calling agent, place a call and poll its transcript, send a text and poll for replies.", - "vendor": { - "name": "AgentPhone", - "url": "https://agentphone.ai", - "contact": "founders@agentphone.to", - "publisher_pubkey": "ed25519:mvVzYABubZwOTzWWQA/TDbRLYkKzmD/x6k/w0nz+zHc=" - }, - "homepage": "https://agentphone.ai", - "source_url": "https://github.com/AgentPhone-AI/skills", - "license": "Apache-2.0", - "categories": [ - "communication", - "phone", - "voice", - "messaging" - ], - "keywords": [ - "phone", - "sms", - "imessage", - "voice", - "calls", - "telephony", - "conversations" - ], - "size": { - "bundle_bytes": 2643572, - "installed_bytes": 6346620 - }, - "compat": { - "min_pilot_version": "1.10.0", - "runtimes": [ - "go" - ] - }, - "methods": [ - { - "name": "agentphone.usage", - "summary": "Account status: plan, number hold limit, and message/call stats. Call this first to orient." - }, - { - "name": "agentphone.list_voices", - "summary": "List available text-to-speech voices (voice_id, name, provider, gender, accent) for use when creating an agent." - }, - { - "name": "agentphone.list_agents", - "summary": "List your calling/texting agents. You get one starter agent on account setup — list before creating more." - }, - { - "name": "agentphone.get_agent", - "summary": "Get one agent's config and its attached numbers." - }, - { - "name": "agentphone.create_agent", - "summary": "Create an agent (phone persona): name, voiceMode (pass \"hosted\"), systemPrompt, voice, modelTier." - }, - { - "name": "agentphone.update_agent", - "summary": "Update an agent's config (only the fields you send change)." - }, - { - "name": "agentphone.delete_agent", - "summary": "Delete an agent. Irreversible — confirm with your human first." - }, - { - "name": "agentphone.attach_number", - "summary": "Attach an existing number to an agent." - }, - { - "name": "agentphone.detach_number", - "summary": "Detach a number from an agent (the number is kept, just unassigned)." - }, - { - "name": "agentphone.list_numbers", - "summary": "List your active phone numbers." - }, - { - "name": "agentphone.buy_number", - "summary": "Provision a new US/CA number (pay-as-you-go $3/mo). Optionally attach to an agent and pick an area code." - }, - { - "name": "agentphone.get_number", - "summary": "Get one phone number (any status, including released)." - }, - { - "name": "agentphone.release_number", - "summary": "Release a number. Irreversible, no refund for the unused period — confirm with your human first." - }, - { - "name": "agentphone.list_messages", - "summary": "List messages on a number (inbound + outbound), newest first. Poll with the after cursor to detect SMS replies." - }, - { - "name": "agentphone.send_message", - "summary": "Send an SMS/iMessage. Auto-delivers over iMessage when both sides support it, else SMS/MMS." - }, - { - "name": "agentphone.react", - "summary": "Send a tapback reaction to a message (iMessage only). reaction: love|like|dislike|laugh|emphasize|question." - }, - { - "name": "agentphone.list_conversations", - "summary": "List conversation threads (one per external contact or iMessage group), newest activity first." - }, - { - "name": "agentphone.get_conversation", - "summary": "Get one conversation with its recent messages." - }, - { - "name": "agentphone.place_call", - "summary": "Place an outbound call. With systemPrompt the AI runs the call autonomously. Returns a call id immediately — poll agentphone.get_call for status + transcript." - }, - { - "name": "agentphone.list_calls", - "summary": "List calls for the account (filter by status, direction)." - }, - { - "name": "agentphone.get_call", - "summary": "Get a call with its embedded transcript. Poll every few seconds until status is completed or failed (the non-websocket way to learn a call outcome)." - }, - { - "name": "agentphone.get_transcript", - "summary": "Get the full ordered transcript of a call (plain JSON, not a stream)." - }, - { - "name": "agentphone.end_call", - "summary": "Terminate an in-progress call. Status/endedAt settle shortly after — keep polling agentphone.get_call." - }, - { - "name": "agentphone.list_contacts", - "summary": "List saved contacts; search filters by name/phone." - }, - { - "name": "agentphone.create_contact", - "summary": "Save a contact (phone is normalized to E.164; 409 if it already exists)." - }, - { - "name": "agentphone.update_contact", - "summary": "Update a contact (only the fields you send change)." - }, - { - "name": "agentphone.delete_contact", - "summary": "Delete a contact. Confirm with your human first." - }, - { - "name": "agentphone.help", - "summary": "Discovery: every method with params, kind, and latency class." - } - ], - "changelog": [ - { - "version": "0.1.0", - "date": "2026-06-24", - "notes": [ - "Initial release — managed-key REST adapter over the AgentPhone API", - "Voice calls (place + poll transcript), SMS/iMessage send + poll, agents, numbers, conversations, contacts" - ] - } - ], - "links": [ - { - "label": "Source", - "url": "https://github.com/AgentPhone-AI/skills" - }, - { - "label": "Website", - "url": "https://agentphone.ai" - } - ] -} diff --git a/submissions/io.pilot.agentphone/submission.json b/submissions/io.pilot.agentphone/submission.json index 47eebb3..682536b 100644 --- a/submissions/io.pilot.agentphone/submission.json +++ b/submissions/io.pilot.agentphone/submission.json @@ -1,33 +1,9 @@ { "id": "io.pilot.agentphone", - "version": "0.1.0", + "version": "0.3.0", "namespace": "agentphone", - "description": "Give your agent a real phone number: place and receive voice calls, send and receive SMS/iMessage, and hold threaded conversations — all over REST. Provision a number, create a calling agent, place a call and poll its transcript, send a text and poll for replies.", - "email": "alex@vulturelabs.io", - "bundle": "io.pilot.agentphone-0.1.0-linux-amd64.tar.gz", - "bundle_sha256": "5d1e6dbc301d42a45e4a84fda2a9a75290ac2f6d4368ba97f58f6cb7f979892a", - "bundles": { - "linux/amd64": { - "file": "io.pilot.agentphone-0.1.0-linux-amd64.tar.gz", - "sha256": "5d1e6dbc301d42a45e4a84fda2a9a75290ac2f6d4368ba97f58f6cb7f979892a" - }, - "linux/arm64": { - "file": "io.pilot.agentphone-0.1.0-linux-arm64.tar.gz", - "sha256": "bbfff26f7ffef897773f4947e9539ff3da188cad4ec69aff29e0ed6f93596890" - }, - "darwin/amd64": { - "file": "io.pilot.agentphone-0.1.0-darwin-amd64.tar.gz", - "sha256": "b5bf81ee5ff440bae870c2c6a8723473475eaa20b9b8db1bc500eaf929d5496b" - }, - "darwin/arm64": { - "file": "io.pilot.agentphone-0.1.0-darwin-arm64.tar.gz", - "sha256": "412b44726220e7c52af5bd19955bdb6190f353c40f2a76ad0289aadf50ab428a" - }, - "windows/amd64": { - "file": "io.pilot.agentphone-0.1.0-windows-amd64.tar.gz", - "sha256": "66806810c5ebbe7eeea056d24b249f1440fb6021d7cf968ff43cc74defdfc884" - } - }, + "description": "Give your AI agent a real US/Canada phone number: place and receive voice calls, send and receive SMS/iMessage, and hold threaded conversations \u2014 all over REST, metered per user against a $5 budget.", + "email": "apps@pilotprotocol.network", "backend": { "base_url": "https://api.agentphone.ai", "auth": "managed", @@ -42,192 +18,1477 @@ "methods": [ { "name": "agentphone.usage", + "description": "Account status: plan, phone-number hold limit (used/limit/remaining), and message/call/webhook stats. Call this first to orient in a session. Read-only; no charge.", + "latency": "fast", "http": { "verb": "GET", "path": "/v1/usage" - } + }, + "params": [] }, { - "name": "agentphone.list_voices", + "name": "agentphone.usage_daily", + "description": "Daily usage breakdown for the last N days (max 365). Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/agents/voices" - } + "path": "/v1/usage/daily" + }, + "params": [ + { + "name": "days", + "type": "string", + "required": false, + "in": "query", + "description": "how many days back (default 30, max 365)" + } + ] }, { - "name": "agentphone.list_agents", + "name": "agentphone.usage_monthly", + "description": "Monthly usage aggregation. Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/agents" - } + "path": "/v1/usage/monthly" + }, + "params": [ + { + "name": "months", + "type": "string", + "required": false, + "in": "query", + "description": "how many months back" + } + ] }, { - "name": "agentphone.get_agent", + "name": "agentphone.usage_by_number", + "description": "Usage broken down per phone number. Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/agents/{agent_id" - } + "path": "/v1/usage/by-number" + }, + "params": [] + }, + { + "name": "agentphone.usage_by_agent", + "description": "Usage broken down per agent over a period. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/usage/by-agent" + }, + "params": [ + { + "name": "period", + "type": "string", + "required": true, + "in": "query", + "description": "week | month | year" + }, + { + "name": "tz", + "type": "string", + "required": false, + "in": "query", + "description": "IANA timezone, e.g. America/New_York" + } + ] + }, + { + "name": "agentphone.list_voices", + "description": "List available text-to-speech voices (voice_id, voice_name, provider, gender, accent, preview_audio_url) across ElevenLabs, Cartesia, OpenAI, and platform voices. gender/accent/preview may be null \u2014 do not crash on missing fields. Use voice_id when creating/updating an agent. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/agents/voices" + }, + "params": [] + }, + { + "name": "agentphone.list_agents", + "description": "List your agents (phone personas: name, voiceMode, model tier, system prompt, attached numbers). You get one starter agent on account setup \u2014 ALWAYS list before creating another. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/agents" + }, + "params": [ + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset (default 0)" + } + ] }, { "name": "agentphone.create_agent", + "description": "Create an agent (phone persona). For AI-driven use pass voiceMode:\"hosted\" explicitly (the backend defaults to \"webhook\", which needs a configured webhook or inbound calls fail). systemPrompt is required for hosted. Pick a voice from agentphone.list_voices. Free (no telephony spend).", + "latency": "med", "http": { "verb": "POST", "path": "/v1/agents" - } + }, + "params": [ + { + "name": "name", + "type": "string", + "required": true, + "in": "body", + "description": "Display name for the agent" + }, + { + "name": "voiceMode", + "type": "string", + "required": false, + "in": "body", + "description": "\"hosted\" (recommended \u2014 AgentPhone runs the LLM) | \"webhook\" (each turn POSTed to your endpoint). Defaults to webhook." + }, + { + "name": "systemPrompt", + "type": "string", + "required": false, + "in": "body", + "description": "Personality/instructions during hosted calls. Required if voiceMode=hosted." + }, + { + "name": "beginMessage", + "type": "string", + "required": false, + "in": "body", + "description": "What the agent says first when a call connects" + }, + { + "name": "voice", + "type": "string", + "required": false, + "in": "body", + "description": "voice_id from agentphone.list_voices (default: Skylar \u2014 Friendly Guide)" + }, + { + "name": "modelTier", + "type": "string", + "required": false, + "in": "body", + "description": "\"turbo\" | \"balanced\" (default) | \"max\" \u2014 speed vs quality" + }, + { + "name": "transferNumber", + "type": "string", + "required": false, + "in": "body", + "description": "E.164 number to transfer calls to on request" + }, + { + "name": "voicemailMessage", + "type": "string", + "required": false, + "in": "body", + "description": "What to say if the callee goes to voicemail" + }, + { + "name": "voiceSpeed", + "type": "number", + "required": false, + "in": "body", + "description": "0.5\u20132.0 speech-speed multiplier (1.0 normal)" + }, + { + "name": "interruptionSensitivity", + "type": "number", + "required": false, + "in": "body", + "description": "0.0\u20131.0, how easily callers can barge in (default 0.8)" + }, + { + "name": "enableBackchannel", + "type": "boolean", + "required": false, + "in": "body", + "description": "agent interjects \"mhmm\" while listening (default true)" + }, + { + "name": "enableMessaging", + "type": "boolean", + "required": false, + "in": "body", + "description": "hosted agent may send/read texts mid-call (default true)" + }, + { + "name": "sttMode", + "type": "string", + "required": false, + "in": "body", + "description": "\"fast\" (default) | \"accurate\" (exact names/numbers)" + }, + { + "name": "ambientSound", + "type": "string", + "required": false, + "in": "body", + "description": "none | office | coffee-shop | outdoor" + }, + { + "name": "denoisingMode", + "type": "string", + "required": false, + "in": "body", + "description": "noise-cancellation (default) | noise-and-background-speech-cancellation" + }, + { + "name": "maxSilenceMs", + "type": "number", + "required": false, + "in": "body", + "description": "hang up after this many ms of caller silence (default 600000)" + }, + { + "name": "language", + "type": "string", + "required": false, + "in": "body", + "description": "BCP-47 locale, e.g. en-US, es-ES, ja-JP" + } + ] + }, + { + "name": "agentphone.get_agent", + "description": "Get one agent's full config and its attached numbers. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/agents/{agent_id}" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + } + ] }, { "name": "agentphone.update_agent", + "description": "Update an agent \u2014 only the fields you send change. Any create field is updatable (systemPrompt, voice, modelTier, \u2026). Free.", + "latency": "med", "http": { "verb": "PATCH", - "path": "/v1/agents/{agent_id" - } + "path": "/v1/agents/{agent_id}" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + }, + { + "name": "systemPrompt", + "type": "string", + "required": false, + "in": "body", + "description": "new instructions (any agent field may be updated)" + }, + { + "name": "voice", + "type": "string", + "required": false, + "in": "body", + "description": "new voice_id" + }, + { + "name": "modelTier", + "type": "string", + "required": false, + "in": "body", + "description": "turbo|balanced|max" + } + ] }, { "name": "agentphone.delete_agent", + "description": "Delete an agent. Irreversible \u2014 clears the agent's references on its numbers/conversations/calls (those are NOT deleted). Confirm with your human first. Free.", + "latency": "fast", "http": { "verb": "DELETE", - "path": "/v1/agents/{agent_id" - } + "path": "/v1/agents/{agent_id}" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + } + ] }, { "name": "agentphone.attach_number", + "description": "Attach an existing number to an agent so the agent can call/text from it. Free.", + "latency": "fast", "http": { "verb": "POST", - "path": "/v1/agents/{agent_id" - } + "path": "/v1/agents/{agent_id}/numbers" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + }, + { + "name": "numberId", + "type": "string", + "required": true, + "in": "body", + "description": "the number id to attach" + } + ] }, { "name": "agentphone.detach_number", + "description": "Detach a number from an agent (the number is kept, just unassigned). Free.", + "latency": "fast", "http": { "verb": "DELETE", - "path": "/v1/agents/{agent_id" - } + "path": "/v1/agents/{agent_id}/numbers/{number_id}" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + }, + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + } + ] + }, + { + "name": "agentphone.list_agent_conversations", + "description": "List an agent's conversation threads, newest activity first (data[], hasMore, total). Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/agents/{agent_id}/conversations" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + }, + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size" + }, + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + } + ] + }, + { + "name": "agentphone.list_agent_calls", + "description": "List an agent's calls (data[], hasMore, total). Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/agents/{agent_id}/calls" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + }, + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size" + }, + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + } + ] }, { "name": "agentphone.list_numbers", + "description": "List your active phone numbers (id, phoneNumber, country, status, agentId). Read-only.", + "latency": "fast", "http": { "verb": "GET", "path": "/v1/numbers" - } + }, + "params": [ + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + } + ] }, { "name": "agentphone.buy_number", + "description": "Provision a new US/CA phone number. COSTS $3.00 from your $5 Pilot budget (402 if it would overdraw). The provisioned number is saved to this host's ~/.pilot/.agentphone so you can recall it later with agentphone.mynumber \u2014 no need to store it yourself. Optionally attach to an agent and request an area code.", + "latency": "med", "http": { "verb": "POST", - "path": "/v1/numbers" - } + "path": "/v1/numbers", + "capture_to": "~/.pilot/.agentphone" + }, + "params": [ + { + "name": "country", + "type": "string", + "required": true, + "in": "body", + "description": "\"US\" | \"CA\"" + }, + { + "name": "areaCode", + "type": "string", + "required": false, + "in": "body", + "description": "3-digit area code, e.g. \"415\"" + }, + { + "name": "agentId", + "type": "string", + "required": false, + "in": "body", + "description": "attach the new number to this agent immediately" + } + ] }, { "name": "agentphone.get_number", + "description": "Get one phone number by id (any status, including released). Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/numbers/{number_id" - } + "path": "/v1/numbers/{number_id}" + }, + "params": [ + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + } + ] }, { "name": "agentphone.release_number", + "description": "Release (delete) a number. IRREVERSIBLE \u2014 the number returns to the carrier pool; no refund for the unused month. Confirm with your human first. Free to call.", + "latency": "fast", "http": { "verb": "DELETE", - "path": "/v1/numbers/{number_id" - } + "path": "/v1/numbers/{number_id}" + }, + "params": [ + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + } + ] }, { - "name": "agentphone.list_messages", + "name": "agentphone.list_number_messages", + "description": "List messages on a number (inbound + outbound), newest first, cursor-paginated. THE non-websocket way to detect SMS replies: poll with the `after` cursor and filter direction==\"inbound\". Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/numbers/{number_id" - } + "path": "/v1/numbers/{number_id}/messages" + }, + "params": [ + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + }, + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size (default 50, max 200)" + }, + { + "name": "before", + "type": "string", + "required": false, + "in": "query", + "description": "ISO timestamp cursor \u2014 messages before this time" + }, + { + "name": "after", + "type": "string", + "required": false, + "in": "query", + "description": "ISO timestamp cursor \u2014 messages after this time (advance it each poll)" + } + ] + }, + { + "name": "agentphone.list_number_calls", + "description": "List calls on a number. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/numbers/{number_id}/calls" + }, + "params": [ + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + }, + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size" + }, + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + } + ] + }, + { + "name": "agentphone.get_contact_card", + "description": "Get the iMessage contact card shown on a number (firstName, lastName, displayName, hasAvatar). iMessage only. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/numbers/{number_id}/contact-card" + }, + "params": [ + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + } + ] + }, + { + "name": "agentphone.set_contact_card", + "description": "Create/replace the iMessage contact card on a number (name + avatar shown to recipients). iMessage only. Free.", + "latency": "fast", + "http": { + "verb": "PUT", + "path": "/v1/numbers/{number_id}/contact-card" + }, + "params": [ + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + }, + { + "name": "firstName", + "type": "string", + "required": false, + "in": "body", + "description": "contact card first name" + }, + { + "name": "lastName", + "type": "string", + "required": false, + "in": "body", + "description": "contact card last name" + }, + { + "name": "displayName", + "type": "string", + "required": false, + "in": "body", + "description": "display name" + }, + { + "name": "avatarUrl", + "type": "string", + "required": false, + "in": "body", + "description": "public HTTPS URL of an avatar image" + } + ] + }, + { + "name": "agentphone.delete_contact_card", + "description": "Remove the iMessage contact card from a number. Free.", + "latency": "fast", + "http": { + "verb": "DELETE", + "path": "/v1/numbers/{number_id}/contact-card" + }, + "params": [ + { + "name": "number_id", + "type": "string", + "required": true, + "in": "path", + "description": "the number id" + } + ] }, { "name": "agentphone.send_message", + "description": "Send an SMS/iMessage. COSTS MONEY (~$0.01\u20130.02, debited from your $5 budget \u2192 402 if over). Auto-delivers over iMessage when both sides support it, else SMS/MMS \u2014 the response `channel` (sms|mms|imessage) tells you how it went. E.164 for `to_number` (or a group id grp_\u2026 for an iMessage group). iMessage-only extras (send_style, reply_to_message_id) are silently ignored on SMS.", + "latency": "med", "http": { "verb": "POST", "path": "/v1/messages" - } + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "body", + "description": "the sending agent (must have a number attached)" + }, + { + "name": "to_number", + "type": "string", + "required": true, + "in": "body", + "description": "recipient in E.164 (+14155551234) or an iMessage group id (grp_\u2026)" + }, + { + "name": "body", + "type": "string", + "required": true, + "in": "body", + "description": "message text (may be empty if sending media only)" + }, + { + "name": "media_url", + "type": "string", + "required": false, + "in": "body", + "description": "public HTTPS URL of one image/file to attach" + }, + { + "name": "media_urls", + "type": "array", + "required": false, + "in": "body", + "description": "multiple media URLs (image carousel on iMessage)" + }, + { + "name": "number_id", + "type": "string", + "required": false, + "in": "body", + "description": "specific number to send from (if the agent has several)" + }, + { + "name": "from_number", + "type": "string", + "required": false, + "in": "body", + "description": "exact E.164 number to send from (alternative to number_id)" + }, + { + "name": "reply_to_message_id", + "type": "string", + "required": false, + "in": "body", + "description": "iMessage only \u2014 thread inline under an earlier message id" + }, + { + "name": "send_style", + "type": "string", + "required": false, + "in": "body", + "description": "iMessage only \u2014 slam|loud|gentle|invisible|confetti|balloons|fireworks|celebration|lasers|spotlight|echo|love" + } + ] }, { "name": "agentphone.react", + "description": "Send a tapback reaction to a message. iMessage ONLY \u2014 returns 400 on SMS. Free.", + "latency": "fast", "http": { "verb": "POST", - "path": "/v1/messages/{message_id" - } + "path": "/v1/messages/{message_id}/reactions" + }, + "params": [ + { + "name": "message_id", + "type": "string", + "required": true, + "in": "path", + "description": "the message id" + }, + { + "name": "reaction", + "type": "string", + "required": true, + "in": "body", + "description": "love | like | dislike | laugh | emphasize | question" + } + ] }, { - "name": "agentphone.list_conversations", + "name": "agentphone.list_calls", + "description": "List calls for the account (filter by status/direction). Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/conversations" - } + "path": "/v1/calls" + }, + "params": [ + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size" + }, + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + }, + { + "name": "status", + "type": "string", + "required": false, + "in": "query", + "description": "in-progress | completed | failed" + }, + { + "name": "direction", + "type": "string", + "required": false, + "in": "query", + "description": "inbound | outbound" + } + ] }, { - "name": "agentphone.get_conversation", + "name": "agentphone.place_call", + "description": "Place an OUTBOUND voice call. COSTS MONEY (per-minute, ~$0.05+, debited from your $5 budget \u2192 402 if over). With `systemPrompt` the AI runs the call autonomously (recommended); without it, each turn is POSTed to the agent's webhook. Returns a call id IMMEDIATELY (async) \u2014 the phone rings in a second or two. Then POLL agentphone.get_call every few seconds until status is completed/failed to read the transcript. Cannot call 911 / N11 / crisis lines (blocked).", + "latency": "med", + "http": { + "verb": "POST", + "path": "/v1/calls" + }, + "params": [ + { + "name": "agentId", + "type": "string", + "required": true, + "in": "body", + "description": "the agent placing the call (must have a number attached)" + }, + { + "name": "toNumber", + "type": "string", + "required": true, + "in": "body", + "description": "recipient in E.164" + }, + { + "name": "systemPrompt", + "type": "string", + "required": false, + "in": "body", + "description": "instructions for an autonomous call (recommended). Runs hosted regardless of the agent's voiceMode." + }, + { + "name": "initialGreeting", + "type": "string", + "required": false, + "in": "body", + "description": "the first line the AI says (auto-generated if omitted)" + }, + { + "name": "fromNumberId", + "type": "string", + "required": false, + "in": "body", + "description": "specific number to call from (if the agent has several)" + }, + { + "name": "voice", + "type": "string", + "required": false, + "in": "body", + "description": "override the agent's default voice for this call" + }, + { + "name": "variables", + "type": "object", + "required": false, + "in": "body", + "description": "template variables injected into the prompt" + } + ] + }, + { + "name": "agentphone.get_call", + "description": "Get a call and its embedded transcripts[]. THE poll target for a call outcome (no websockets): call every few seconds until status is completed or failed (in-progress means partial/empty transcript). Also carries durationSeconds, startedAt, endedAt. Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/conversations/{conversation_id" - } + "path": "/v1/calls/{call_id}" + }, + "params": [ + { + "name": "call_id", + "type": "string", + "required": true, + "in": "path", + "description": "the call id" + } + ] }, { - "name": "agentphone.place_call", + "name": "agentphone.end_call", + "description": "Terminate an in-progress call. status/endedAt settle shortly after via the provider \u2014 keep polling agentphone.get_call until terminal. Free.", + "latency": "fast", "http": { "verb": "POST", - "path": "/v1/calls" - } + "path": "/v1/calls/{call_id}/end" + }, + "params": [ + { + "name": "call_id", + "type": "string", + "required": true, + "in": "path", + "description": "the call id" + } + ] }, { - "name": "agentphone.list_calls", + "name": "agentphone.get_transcript", + "description": "Get the full ordered transcript of a call as plain JSON (user utterance + agent response per turn). This is the REST/polling alternative to the SSE live-transcript stream \u2014 the adapter never uses the stream. Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/calls" - } + "path": "/v1/calls/{call_id}/transcript" + }, + "params": [ + { + "name": "call_id", + "type": "string", + "required": true, + "in": "path", + "description": "the call id" + } + ] }, { - "name": "agentphone.get_call", + "name": "agentphone.list_conversations", + "description": "List conversation threads (one per external contact or iMessage group), sorted by lastMessageAt desc (data[], hasMore, total). Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/calls/{call_id" - } + "path": "/v1/conversations" + }, + "params": [ + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + } + ] }, { - "name": "agentphone.get_transcript", + "name": "agentphone.get_conversation", + "description": "Get one conversation with its recent messages (participant, isGroup, group roster, messageCount, metadata). Read-only.", + "latency": "fast", "http": { "verb": "GET", - "path": "/v1/calls/{call_id" - } + "path": "/v1/conversations/{conversation_id}" + }, + "params": [ + { + "name": "conversation_id", + "type": "string", + "required": true, + "in": "path", + "description": "the conversation id" + }, + { + "name": "message_limit", + "type": "string", + "required": false, + "in": "query", + "description": "how many recent messages to include" + } + ] }, { - "name": "agentphone.end_call", + "name": "agentphone.update_conversation", + "description": "Update a conversation's `metadata` (attach custom AI context/state to the thread). Free.", + "latency": "fast", + "http": { + "verb": "PATCH", + "path": "/v1/conversations/{conversation_id}" + }, + "params": [ + { + "name": "conversation_id", + "type": "string", + "required": true, + "in": "path", + "description": "the conversation id" + }, + { + "name": "metadata", + "type": "object", + "required": true, + "in": "body", + "description": "arbitrary JSON context to store on the thread" + } + ] + }, + { + "name": "agentphone.list_conversation_messages", + "description": "List a conversation's messages, cursor-paginated (data[], hasMore). Poll with `after` to catch new inbound replies in a thread. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/conversations/{conversation_id}/messages" + }, + "params": [ + { + "name": "conversation_id", + "type": "string", + "required": true, + "in": "path", + "description": "the conversation id" + }, + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size (default 50, max 200)" + }, + { + "name": "before", + "type": "string", + "required": false, + "in": "query", + "description": "ISO timestamp cursor" + }, + { + "name": "after", + "type": "string", + "required": false, + "in": "query", + "description": "ISO timestamp cursor" + } + ] + }, + { + "name": "agentphone.typing", + "description": "Show a typing indicator before you reply. iMessage only, best-effort, auto-expires (no stop call). Free.", + "latency": "fast", "http": { "verb": "POST", - "path": "/v1/calls/{call_id" - } + "path": "/v1/conversations/{conversation_id}/typing" + }, + "params": [ + { + "name": "conversation_id", + "type": "string", + "required": true, + "in": "path", + "description": "the conversation id" + } + ] + }, + { + "name": "agentphone.set_background", + "description": "Set a chat background image for a conversation. iMessage only. Free.", + "latency": "fast", + "http": { + "verb": "POST", + "path": "/v1/conversations/{conversation_id}/background" + }, + "params": [ + { + "name": "conversation_id", + "type": "string", + "required": true, + "in": "path", + "description": "the conversation id" + }, + { + "name": "image_url", + "type": "string", + "required": true, + "in": "body", + "description": "public HTTPS URL of the background image" + } + ] + }, + { + "name": "agentphone.clear_background", + "description": "Clear a conversation's chat background. iMessage only. Free.", + "latency": "fast", + "http": { + "verb": "DELETE", + "path": "/v1/conversations/{conversation_id}/background" + }, + "params": [ + { + "name": "conversation_id", + "type": "string", + "required": true, + "in": "path", + "description": "the conversation id" + } + ] }, { "name": "agentphone.list_contacts", + "description": "List saved contacts (data[], hasMore, total); `search` filters by name/phone. Read-only.", + "latency": "fast", "http": { "verb": "GET", "path": "/v1/contacts" - } + }, + "params": [ + { + "name": "search", + "type": "string", + "required": false, + "in": "query", + "description": "filter by name or phone" + }, + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size" + }, + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + } + ] }, { "name": "agentphone.create_contact", + "description": "Save a contact so you can look them up by name later. phoneNumber is normalized to E.164; returns 409 if the phone already exists. Free.", + "latency": "fast", "http": { "verb": "POST", "path": "/v1/contacts" - } + }, + "params": [ + { + "name": "phoneNumber", + "type": "string", + "required": true, + "in": "body", + "description": "contact phone, E.164" + }, + { + "name": "name", + "type": "string", + "required": true, + "in": "body", + "description": "contact name" + }, + { + "name": "email", + "type": "string", + "required": false, + "in": "body", + "description": "optional email" + }, + { + "name": "notes", + "type": "string", + "required": false, + "in": "body", + "description": "optional freeform notes" + } + ] + }, + { + "name": "agentphone.get_contact", + "description": "Get one contact by id. Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/contacts/{contact_id}" + }, + "params": [ + { + "name": "contact_id", + "type": "string", + "required": true, + "in": "path", + "description": "the contact id" + } + ] }, { "name": "agentphone.update_contact", + "description": "Update a contact \u2014 only the fields you send change (phone is re-normalized; 409 on conflict). Free.", + "latency": "fast", "http": { "verb": "PATCH", - "path": "/v1/contacts/{contact_id" - } + "path": "/v1/contacts/{contact_id}" + }, + "params": [ + { + "name": "contact_id", + "type": "string", + "required": true, + "in": "path", + "description": "the contact id" + }, + { + "name": "name", + "type": "string", + "required": false, + "in": "body", + "description": "new name" + }, + { + "name": "phoneNumber", + "type": "string", + "required": false, + "in": "body", + "description": "new phone, E.164" + }, + { + "name": "email", + "type": "string", + "required": false, + "in": "body", + "description": "new email" + }, + { + "name": "notes", + "type": "string", + "required": false, + "in": "body", + "description": "new notes" + } + ] }, { "name": "agentphone.delete_contact", + "description": "Delete a contact. Confirm with your human first. Free.", + "latency": "fast", "http": { "verb": "DELETE", - "path": "/v1/contacts/{contact_id" - } + "path": "/v1/contacts/{contact_id}" + }, + "params": [ + { + "name": "contact_id", + "type": "string", + "required": true, + "in": "path", + "description": "the contact id" + } + ] + }, + { + "name": "agentphone.get_webhook", + "description": "Get the account-level webhook config. Read-only. (Polling is the default event model for this adapter; webhooks are optional.)", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/webhooks" + }, + "params": [] + }, + { + "name": "agentphone.set_webhook", + "description": "Set the account-level webhook URL (returns a signing `secret`; a new one each call). NOTE: on the shared Pilot AgentPhone account this is a GLOBAL setting \u2014 prefer per-agent webhooks or polling. Free.", + "latency": "fast", + "http": { + "verb": "POST", + "path": "/v1/webhooks" + }, + "params": [ + { + "name": "url", + "type": "string", + "required": true, + "in": "body", + "description": "your HTTPS endpoint that receives events" + }, + { + "name": "contextLimit", + "type": "number", + "required": false, + "in": "body", + "description": "conversation context to include" + }, + { + "name": "timeout", + "type": "number", + "required": false, + "in": "body", + "description": "delivery timeout" + } + ] + }, + { + "name": "agentphone.delete_webhook", + "description": "Remove the account-level webhook. Global on the shared account \u2014 use with care. Free.", + "latency": "fast", + "http": { + "verb": "DELETE", + "path": "/v1/webhooks" + }, + "params": [] + }, + { + "name": "agentphone.list_webhook_deliveries", + "description": "List recent webhook delivery attempts (items[], total). Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/webhooks/deliveries" + }, + "params": [ + { + "name": "limit", + "type": "string", + "required": false, + "in": "query", + "description": "page size" + }, + { + "name": "offset", + "type": "string", + "required": false, + "in": "query", + "description": "pagination offset" + }, + { + "name": "hours", + "type": "string", + "required": false, + "in": "query", + "description": "look-back window in hours" + } + ] + }, + { + "name": "agentphone.webhook_delivery_stats", + "description": "Aggregated webhook delivery stats over the last N hours (success/failed/pending, byEventType, byHour). Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/webhooks/deliveries/stats" + }, + "params": [ + { + "name": "hours", + "type": "string", + "required": false, + "in": "query", + "description": "look-back window in hours" + } + ] + }, + { + "name": "agentphone.test_webhook", + "description": "Send a synthetic test event to verify your endpoint is reachable and verifying signatures. Free.", + "latency": "fast", + "http": { + "verb": "POST", + "path": "/v1/webhooks/test" + }, + "params": [ + { + "name": "agentId", + "type": "string", + "required": false, + "in": "query", + "description": "test the webhook for a specific agent" + } + ] + }, + { + "name": "agentphone.get_agent_webhook", + "description": "Get an agent-specific webhook (overrides the account default for that agent). Read-only.", + "latency": "fast", + "http": { + "verb": "GET", + "path": "/v1/agents/{agent_id}/webhook" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + } + ] + }, + { + "name": "agentphone.set_agent_webhook", + "description": "Set an agent-specific webhook URL (overrides the account default for THIS agent only \u2014 safer than the account-level webhook on a shared account). Free.", + "latency": "fast", + "http": { + "verb": "POST", + "path": "/v1/agents/{agent_id}/webhook" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + }, + { + "name": "url", + "type": "string", + "required": true, + "in": "body", + "description": "your HTTPS endpoint" + }, + { + "name": "contextLimit", + "type": "number", + "required": false, + "in": "body", + "description": "context to include" + }, + { + "name": "timeout", + "type": "number", + "required": false, + "in": "body", + "description": "delivery timeout" + } + ] + }, + { + "name": "agentphone.delete_agent_webhook", + "description": "Delete an agent-specific webhook (the agent falls back to the account default). Free.", + "latency": "fast", + "http": { + "verb": "DELETE", + "path": "/v1/agents/{agent_id}/webhook" + }, + "params": [ + { + "name": "agent_id", + "type": "string", + "required": true, + "in": "path", + "description": "the agent id" + } + ] + }, + { + "name": "agentphone.mynumber", + "description": "Recall the phone number(s) THIS daemon provisioned (local, no backend call, free). Reads ~/.pilot/.agentphone, populated automatically by agentphone.buy_number. Returns {entries:[{id,phoneNumber,status,agentId,...}]} \u2014 empty if this host hasn't provisioned one yet. Use it to find 'my number' without listing the shared account.", + "latency": "fast", + "local": { + "store": "~/.pilot/.agentphone" + }, + "params": [] } - ] + ], + "listing": { + "display_name": "AgentPhone", + "tagline": "A real phone number for your agent \u2014 voice calls, SMS/iMessage, and conversations over REST", + "app_description": "# AgentPhone \u2014 a real phone number for your AI agent\n\nAgentPhone gives your agent its **own real US/Canada phone number**: place and receive **voice calls**, send and receive **SMS & iMessage**, and hold threaded **conversations** with real people \u2014 all over plain REST. This is the managed Pilot front door: you bring **nothing** (no signup, no API key). Pilot holds one AgentPhone master key behind the broker and gives **each Pilot user a $5 budget**; calls and texts debit against it, and once it's spent the paid endpoints return `402 Payment Required` (reads stay free).\n\n## What you can do\n\n- **Call people.** `agentphone.place_call` with a `systemPrompt` runs an autonomous voice call \u2014 the phone rings in ~1\u20132s and the AI holds the conversation. Book a reservation, chase a shipment, return a missed call, or call another agent.\n- **Text people.** `agentphone.send_message` delivers over **iMessage** when both sides support it (unlocking threaded replies, tapback reactions, send effects, typing indicators, group chats) and transparently falls back to **SMS/MMS** otherwise \u2014 same call either way.\n- **Answer & follow up.** Poll `agentphone.list_number_messages` / `agentphone.list_conversation_messages` for inbound texts and `agentphone.get_call` for call transcripts \u2014 **no websockets required**.\n- **Manage your setup.** Buy/release numbers, create and tune agents (voice, model tier, system prompt, ambience), keep an address book of contacts, and attach numbers to agents.\n\n## How it works (no signup step)\n\nBecause this is the **managed** app, the AgentPhone account already exists behind the Pilot broker \u2014 you skip the `/v0/agent/sign-up` + `/v0/agent/verify` flow entirely. Just call the `/v1` methods below; the broker authenticates you as your Pilot identity, injects the master key, meters your spend, and forwards to `https://api.agentphone.ai`.\n\n**Async, poll-based (no streaming):**\n1. `agentphone.place_call` \u2192 returns a call `id` immediately; the call runs in the background.\n2. Poll `agentphone.get_call` every few seconds until `status` is `completed` or `failed`, then read `transcripts[]` (or `agentphone.get_transcript`).\n3. For inbound SMS, poll `agentphone.list_number_messages` with the `after` cursor and filter `direction == \"inbound\"`.\n\n## Critical gotchas (read once)\n\n- **You cannot call 911**, N11 numbers, or crisis lines \u2014 they're blocked. If your human has an emergency, tell them to dial directly.\n- **Released numbers are gone forever** \u2014 no refund for the unused month. Confirm before `agentphone.release_number`.\n- **Always use E.164**: `+14155551234` \u2713 \u2014 never `(415) 555-1234` or `415-555-1234`. Assume `+1` for a bare US number and confirm if it matters.\n- **Inbound calls need hosted mode OR a webhook.** Create agents with `voiceMode: \"hosted\"` explicitly (the backend defaults to `webhook`, which fails inbound if no webhook is set).\n- **iMessage-only features** (reactions, send effects, typing, backgrounds, contact cards) are silently ignored on SMS \u2014 check the response `channel`.\n- **Don't spam.** Unsolicited bulk calls/texts are illegal and get the account suspended.\n\n## Cost & the $5 budget\n\nReads are free. Spending operations debit your per-user $5 Pilot budget: buying a number (**$3.00/mo**), placing a call (**per-minute**), and sending a text (**~$0.01\u20130.02**). When a call would overdraw, the broker returns `402` before anything is charged, and every response carries your remaining balance in the `X-Pilot-Credits-Remaining` header (micro-dollars).\n\nEvery method's parameters, kind, and latency class are discoverable at runtime via `agentphone.help`.\n", + "license": "Apache-2.0", + "homepage": "https://agentphone.ai", + "source_url": "https://github.com/AgentPhone-AI/skills", + "categories": [ + "communication", + "phone", + "voice", + "messaging" + ], + "keywords": [ + "phone", + "sms", + "imessage", + "voice", + "calls", + "telephony", + "conversations", + "agent" + ] + }, + "vendor": { + "name": "AgentPhone", + "url": "https://agentphone.ai", + "contact": "founders@agentphone.to" + } }