Code Examples

Copy-paste examples to get up and running quickly. Each example is self-contained and production-ready.

JavaScript / Node.js

A complete script that provisions a number, registers a webhook, and queries conversations and calls.

sms-api.js
1const API_KEY = "YOUR_API_KEY";
2const BASE_URL = "https://api.agentphone.to";
3
4const headers = {
5 Authorization: `Bearer ${API_KEY}`,
6 "Content-Type": "application/json",
7};
8
9async function createNumber() {
10 const res = await fetch(`${BASE_URL}/v1/numbers`, {
11 method: "POST",
12 headers,
13 body: JSON.stringify({ country: "US" }),
14 });
15 return res.json();
16}
17
18async function registerWebhook(url) {
19 const res = await fetch(`${BASE_URL}/v1/webhooks`, {
20 method: "POST",
21 headers,
22 body: JSON.stringify({ url }),
23 });
24 return res.json();
25}
26
27async function listConversations() {
28 const res = await fetch(`${BASE_URL}/v1/conversations`, { headers });
29 return res.json();
30}
31
32async function listCalls() {
33 const res = await fetch(`${BASE_URL}/v1/calls`, { headers });
34 return res.json();
35}
36
37async function getCall(callId) {
38 const res = await fetch(`${BASE_URL}/v1/calls/${callId}`, { headers });
39 return res.json();
40}
41
42async function makeOutboundCall(agentId, toNumber, fromNumberId) {
43 const body = { agentId, toNumber };
44 // Optional: pick which of the agent's numbers to call from.
45 // If omitted, the agent's first assigned number is used.
46 if (fromNumberId) body.fromNumberId = fromNumberId;
47
48 const res = await fetch(`${BASE_URL}/v1/calls`, {
49 method: "POST",
50 headers,
51 body: JSON.stringify(body),
52 });
53 return res.json();
54}
55
56// --- Usage ---
57const number = await createNumber();
58console.log(`Created: ${number.phoneNumber}`);
59
60const webhook = await registerWebhook("https://my-server.com/webhook");
61console.log(`Webhook secret: ${webhook.secret}`);
62
63const convos = await listConversations();
64console.log(`${convos.total} conversations`);
65
66const calls = await listCalls();
67console.log(`${calls.total} calls`);
68
69if (calls.data.length > 0) {
70 const call = await getCall(calls.data[0].id);
71 console.log(`Call transcripts: ${call.transcripts.length}`);
72}

Express.js Webhook Handler

Receives webhooks, verifies HMAC signatures, and routes SMS / voice events.

webhook.js
1const express = require("express");
2const crypto = require("crypto");
3const app = express();
4
5const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
6
7app.use("/webhook", express.raw({ type: "application/json" }));
8
9function verifyWebhook(payload, signature, secret) {
10 const expected = crypto
11 .createHmac("sha256", secret)
12 .update(payload)
13 .digest("hex");
14 return signature === `sha256=${expected}`;
15}
16
17app.post("/webhook", (req, res) => {
18 const signature = req.headers["x-webhook-signature"];
19
20 if (!verifyWebhook(req.body, signature, WEBHOOK_SECRET)) {
21 return res.status(401).send("Invalid signature");
22 }
23
24 const payload = JSON.parse(req.body.toString());
25
26 if (payload.event === "agent.message") {
27 const { channel, data } = payload;
28
29 if (channel === "sms") {
30 console.log(`SMS from ${data.from}: ${data.message}`);
31 processMessage(data).catch(console.error);
32 return res.status(200).send("OK");
33 }
34
35 if (channel === "voice") {
36 console.log(`Voice from ${data.from}: ${data.transcript}`);
37 processVoice(data)
38 .then((response) => {
39 res.status(200).json({ text: response, voice: "Polly.Amy", hangup: false });
40 })
41 .catch(() => {
42 res.status(200).json({ text: "Sorry, I encountered an error." });
43 });
44 return;
45 }
46 }
47
48 res.status(200).send("OK");
49});
50
51async function processMessage(message) {
52 // Your message processing logic (AI agent, database, queue, etc.)
53}
54
55async function processVoice(data) {
56 // Your voice processing logic — return a string to speak
57 return "Thanks for calling! How can I help?";
58}
59
60app.listen(3000, () => console.log("Webhook server running on port 3000"));

Flask Webhook Handler

Python equivalent with HMAC verification and SMS/voice routing.

webhook.py
1from flask import Flask, request, jsonify
2import hmac
3import hashlib
4import os
5
6app = Flask(__name__)
7WEBHOOK_SECRET = os.environ.get("WEBHOOK_SECRET")
8
9
10def verify_webhook(payload_body, signature, secret):
11 expected = hmac.new(
12 secret.encode(), payload_body, hashlib.sha256
13 ).hexdigest()
14 return hmac.compare_digest(f"sha256={expected}", signature)
15
16
17@app.route("/webhook", methods=["POST"])
18def webhook():
19 signature = request.headers.get("X-Webhook-Signature")
20
21 if not verify_webhook(request.data, signature, WEBHOOK_SECRET):
22 return jsonify({"error": "Invalid signature"}), 401
23
24 payload = request.json
25
26 if payload.get("event") == "agent.message":
27 channel = payload.get("channel")
28 data = payload.get("data", {})
29
30 if channel == "sms":
31 print(f"SMS from {data['from']}: {data['message']}")
32 return jsonify({"status": "ok"}), 200
33
34 if channel == "voice":
35 transcript = data.get("transcript", "")
36 ai_response = get_ai_response(transcript)
37 return jsonify({"text": ai_response, "voice": "Polly.Amy", "hangup": False}), 200
38
39 return jsonify({"status": "ok"}), 200
40
41
42def get_ai_response(transcript):
43 # Replace with your LLM call (OpenAI, Anthropic, etc.)
44 return f"I heard you say: {transcript}. How can I help?"
45
46
47if __name__ == "__main__":
48 app.run(port=3000)

Voice Webhook with OpenAI

A voice-specific handler that pipes caller transcripts through GPT-4 and returns spoken responses.

voice_webhook.py
1from flask import Flask, request, jsonify
2import openai
3import os
4
5app = Flask(__name__)
6openai.api_key = os.environ.get("OPENAI_API_KEY")
7
8
9@app.route("/webhook", methods=["POST"])
10def webhook():
11 payload = request.json
12
13 if payload.get("event") == "agent.message":
14 channel = payload.get("channel")
15 data = payload.get("data", {})
16
17 if channel == "voice":
18 transcript = data.get("transcript", "")
19 try:
20 response = openai.ChatCompletion.create(
21 model="gpt-4",
22 messages=[
23 {"role": "system", "content": "You are a helpful customer service assistant."},
24 {"role": "user", "content": transcript},
25 ],
26 max_tokens=150,
27 )
28 ai_text = response.choices[0].message.content
29 return jsonify({"text": ai_text, "voice": "Polly.Amy", "hangup": False}), 200
30 except Exception as e:
31 print(f"AI error: {e}")
32 return jsonify({"text": "Sorry, I encountered an error."}), 200
33
34 if channel == "sms":
35 print(f"SMS from {data['from']}: {data['message']}")
36 return jsonify({"status": "ok"}), 200
37
38 return jsonify({"status": "ok"}), 200
39
40
41if __name__ == "__main__":
42 app.run(port=3000)

Next.js API Route

Webhook handler as a Next.js Pages Router API route.

pages/api/webhook.js
1import crypto from "crypto";
2
3const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
4
5function verifyWebhook(payload, signature, secret) {
6 const expected = crypto
7 .createHmac("sha256", secret)
8 .update(payload)
9 .digest("hex");
10 return signature === `sha256=${expected}`;
11}
12
13export default async function handler(req, res) {
14 if (req.method !== "POST") {
15 return res.status(405).json({ error: "Method not allowed" });
16 }
17
18 const signature = req.headers["x-webhook-signature"];
19 const rawBody = JSON.stringify(req.body);
20
21 if (!verifyWebhook(rawBody, signature, WEBHOOK_SECRET)) {
22 return res.status(401).json({ error: "Invalid signature" });
23 }
24
25 const payload = req.body;
26
27 if (payload.event === "agent.message") {
28 const { channel, data } = payload;
29
30 if (channel === "sms") {
31 await processMessage(data);
32 }
33
34 if (channel === "voice") {
35 const response = await processVoice(data);
36 return res.status(200).json({ text: response, voice: "Polly.Amy", hangup: false });
37 }
38 }
39
40 res.status(200).json({ status: "ok" });
41}
42
43async function processMessage(message) {
44 console.log(`Processing message: ${message.body}`);
45}
46
47async function processVoice(data) {
48 return "Thanks for calling! How can I help?";
49}

Python API Client

A standalone script that provisions a number, registers a webhook, and lists conversations.

sms_api.py
1import requests
2
3API_KEY = "YOUR_API_KEY"
4BASE_URL = "https://api.agentphone.to"
5headers = {"Authorization": f"Bearer {API_KEY}"}
6
7# Create a phone number
8number = requests.post(
9 f"{BASE_URL}/v1/numbers",
10 headers={**headers, "Content-Type": "application/json"},
11 json={"country": "US"},
12).json()
13print(f"Created: {number['phoneNumber']}")
14
15# Register webhook
16webhook = requests.post(
17 f"{BASE_URL}/v1/webhooks",
18 headers={**headers, "Content-Type": "application/json"},
19 json={"url": "https://my-server.com/webhook"},
20).json()
21print(f"Webhook secret: {webhook['secret']}")
22
23# List conversations
24convos = requests.get(f"{BASE_URL}/v1/conversations", headers=headers).json()
25print(f"{convos['total']} conversations")
26
27# Get a specific conversation
28if convos["data"]:
29 conv = requests.get(
30 f"{BASE_URL}/v1/conversations/{convos['data'][0]['id']}",
31 headers=headers,
32 ).json()
33 print(f"Conversation with {conv['participant']}: {conv['messageCount']} messages")
34
35# Make an outbound call (optionally pick which number to call from)
36call = requests.post(
37 f"{BASE_URL}/v1/calls",
38 headers={**headers, "Content-Type": "application/json"},
39 json={
40 "agentId": "AGENT_ID",
41 "toNumber": "+14155551234",
42 # "fromNumberId": "NUMBER_ID", # optional — defaults to agent's first number
43 },
44).json()
45print(f"Call {call['id']}: {call['fromNumber']} -> {call['toNumber']}")