> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.agentphone.ai/documentation/sdks/python/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.agentphone.ai/_mcp/server. # Python SDK > Official Python SDK for the AgentPhone API The official AgentPhone Python library provides convenient access to the AgentPhone API with both synchronous and asynchronous clients. [![PyPI](https://img.shields.io/pypi/v/agentphone)](https://pypi.org/project/agentphone/) ## Installation ```sh pip install agentphone ``` For async support: ```sh pip install agentphone[async] ``` ## Quick start ```python from agentphone import AgentPhone client = AgentPhone(api_key="YOUR_API_KEY") # Create an agent agent = client.agents.create(name="Support Bot") # Buy a number and attach it number = client.numbers.buy(country="US", agent_id=agent.id) # Make an AI-powered call call = client.calls.make( agent_id=agent.id, to_number="+15559876543", system_prompt="You are a helpful support assistant.", initial_greeting="Hi, this is Support Bot!", ) ``` ## Async usage ```python from agentphone import AsyncAgentPhone async with AsyncAgentPhone(api_key="YOUR_API_KEY") as client: agents = await client.agents.list() call = await client.calls.make( agent_id=agents.data[0].id, to_number="+15559876543", system_prompt="You are a helpful assistant.", ) ``` ## Resources ### Agents ```python # List all agents agents = client.agents.list(limit=20, offset=0) # Create an agent with voice configuration agent = client.agents.create( name="Support Bot", description="Handles customer inquiries", voice_mode="hosted", # "hosted" for built-in AI, "webhook" for custom system_prompt="You are a friendly support agent.", begin_message="Hi! How can I help?", voice="11labs-Brian", # see list_voices() transfer_number="+15551234567", # optional: transfer calls here voicemail_message="Leave a message after the beep.", ) # Get agent details agent = client.agents.get(agent_id="agt_abc123") # Update an agent agent = client.agents.update( agent_id="agt_abc123", name="Updated Bot", system_prompt="New prompt here.", ) # Delete an agent client.agents.delete(agent_id="agt_abc123") # Attach / detach a number client.agents.attach_number(agent_id="agt_abc123", number_id="num_xyz789") client.agents.detach_number(agent_id="agt_abc123", number_id="num_xyz789") # List calls and conversations for an agent calls = client.agents.list_calls(agent_id="agt_abc123", limit=20) convos = client.agents.list_conversations(agent_id="agt_abc123", limit=20) # List available voices voices = client.agents.list_voices() ``` #### Per-agent webhooks ```python # Set a webhook for a specific agent (overrides project default) webhook = client.agents.set_webhook( agent_id="agt_abc123", url="https://your-server.com/agent-hook", context_limit=10, timeout=30, ) # Get / delete an agent's webhook webhook = client.agents.get_webhook(agent_id="agt_abc123") client.agents.delete_webhook(agent_id="agt_abc123") # View deliveries and send a test event deliveries = client.agents.list_webhook_deliveries(agent_id="agt_abc123", limit=50) client.agents.test_webhook(agent_id="agt_abc123") ``` ### Numbers ```python # List numbers numbers = client.numbers.list(limit=20, offset=0) # Buy a new number number = client.numbers.buy( country="US", area_code="415", # optional, US/CA only agent_id="agt_abc123", # optional: attach immediately ) # Get messages for a number messages = client.numbers.get_messages(number_id="num_xyz789", limit=50) # List calls for a number calls = client.numbers.list_calls(number_id="num_xyz789", limit=20) # Release a number (irreversible) client.numbers.release(number_id="num_xyz789") ``` ### Messages ```python # Send an SMS or iMessage client.messages.send( agent_id="agt_abc123", to_number="+15559876543", body="Hello from my agent!", media_url="https://example.com/image.png", # optional (MMS/iMessage) number_id="num_xyz789", # optional: send from specific number ) # Send a tapback reaction (iMessage only) client.messages.react( message_id="msg_abc123", reaction="love", # love, like, dislike, laugh, emphasize, question ) ``` ### Contacts ```python # List contacts contacts = client.contacts.list(limit=50, search="Alice") # Create a contact contact = client.contacts.create( phone_number="+15559876543", name="Alice Smith", email="alice@example.com", notes="VIP customer", ) # Get / update / delete contact = client.contacts.get(contact_id="ct_abc123") contact = client.contacts.update(contact_id="ct_abc123", name="Alice Johnson") client.contacts.delete(contact_id="ct_abc123") ``` ### Conversations ```python # List all conversations convos = client.conversations.list(limit=20, offset=0) # Get a conversation with messages convo = client.conversations.get( conversation_id="conv_abc123", message_limit=50, ) # Get messages with cursor pagination messages = client.conversations.get_messages( conversation_id="conv_abc123", limit=50, before="msg_older", # cursor pagination after="msg_newer", ) # Update conversation metadata convo = client.conversations.update( conversation_id="conv_abc123", metadata={"priority": "high", "assigned_to": "team-a"}, ) ``` ### Calls ```python # List calls with optional filters calls = client.calls.list( limit=20, status="completed", # optional filter direction="outbound", # optional filter type="conversation", # optional filter search="+1415", # optional search ) # Get a call with transcript call = client.calls.get(call_id="call_abc123") # Make an outbound call with built-in AI (no webhook needed) call = client.calls.make( agent_id="agt_abc123", to_number="+15559876543", system_prompt="You are a support agent helping with order inquiries.", initial_greeting="Hello! How can I help you today?", from_number_id="num_xyz789", # optional: call from specific number voice="11labs-Brian", # optional: override agent voice ) # Make a webhook-based call (omit system_prompt, requires webhook configured) call = client.calls.make( agent_id="agt_abc123", to_number="+15559876543", initial_greeting="Hello!", ) # Create a web-based call (browser) web_call = client.calls.create_web_call( agent_id="agt_abc123", metadata={"source": "dashboard"}, ) # Get transcript separately transcript = client.calls.get_transcript(call_id="call_abc123") # Stream transcript via Server-Sent Events for event in client.calls.stream_transcript(call_id="call_abc123"): if event["event"] == "turn": print(f"[{event['data']['role']}] {event['data']['content']}") elif event["event"] == "ended": print(f"Call ended ({event['data']['durationSeconds']}s)") ``` ### Webhooks (project-level) ```python # Get webhook config webhook = client.webhooks.get() # Set or update webhook webhook = client.webhooks.set( url="https://your-server.com/webhook", context_limit=10, # 0-50 recent messages in payloads timeout=30, # response timeout in seconds (5-120) ) print(webhook.secret) # save this! # View delivery history deliveries = client.webhooks.list_deliveries(limit=50) # Get delivery statistics stats = client.webhooks.get_delivery_stats(hours=24) print(f"Success rate: {stats.success_rate}%") all_time = client.webhooks.get_all_time_stats() # Test webhook client.webhooks.test(agent_id="agt_abc123") # optional: test for specific agent # Delete webhook client.webhooks.delete() ``` ### Usage ```python # Get current usage summary (plan, limits, stats) usage = client.usage.get() print(f"Plan: {usage.plan.name}") print(f"Numbers: {usage.numbers.used}/{usage.numbers.limit}") print(f"Messages (30d): {usage.stats.messages_last_30d}") print(f"Calls (30d): {usage.stats.calls_last_30d}") # Daily breakdown daily = client.usage.get_daily(days=30) for day in daily.data: print(f"{day.date}: {day.messages} msgs, {day.calls} calls") # Monthly breakdown monthly = client.usage.get_monthly(months=6) ``` ## Error handling ```python from agentphone import ( AgentPhoneError, AuthenticationError, NotFoundError, RateLimitError, ) try: agent = client.agents.get(agent_id="bad-id") except NotFoundError: print("Agent not found") except AuthenticationError: print("Invalid API key") except RateLimitError: print("Too many requests") except AgentPhoneError as e: print(f"API error {e.status}: {e.message}") ``` ## Webhook verification Each delivery is signed over `"{timestamp}.{raw_body}"`. The signature arrives in the `X-Webhook-Signature` header and the timestamp in `X-Webhook-Timestamp`, so pass both along with the raw body and your secret. Both helpers also enforce a 5-minute replay window by default (`tolerance=300`; pass `tolerance=None` to skip it). Requires `agentphone >= 0.17.0`. ```python from agentphone import construct_event, verify_webhook, WebhookVerificationError # payload = raw request body (bytes) # signature = X-Webhook-Signature header # secret = your webhook secret # timestamp = X-Webhook-Timestamp header # Option 1: Verify signature only try: verify_webhook(payload, signature, secret, timestamp) except WebhookVerificationError: print("Invalid or stale signature") # Option 2: Verify + parse into a typed event event = construct_event(payload, signature, secret, timestamp) if event.event == "agent.message": print(event.data.message) print(event.data.from_number) print(event.channel) # "sms", "imessage", or "voice" for item in event.recent_history: # recent conversation context print(f" [{item.direction}] {item.content}") print(event.conversation_state) # custom metadata ``` ### Flask example ```python from flask import Flask, request, jsonify from agentphone import construct_event app = Flask(__name__) @app.route("/webhook", methods=["POST"]) def webhook(): event = construct_event( payload=request.data, signature=request.headers.get("X-Webhook-Signature", ""), secret="your_webhook_secret", timestamp=request.headers.get("X-Webhook-Timestamp", ""), ) # Respond to the caller return jsonify({"response": f"Got your message: {event.data.message}"}) ``` ## Advanced ### Context manager ```python with AgentPhone(api_key="YOUR_API_KEY") as client: agents = client.agents.list() # session is automatically closed ``` ### Custom base URL and timeout ```python client = AgentPhone( api_key="YOUR_API_KEY", base_url="https://api.agentphone.ai", timeout=30.0, ) ``` ## Links * [PyPI package](https://pypi.org/project/agentphone/) * [GitHub organization](https://github.com/AgentPhone-AI) > Official Python SDK for the AgentPhone API