Build on AI Phone 360
Programmatically access your calls, transcripts, recordings and contacts, send SMS, react to events in real time with webhooks, and let your AI receptionist call your own systems live during a conversation — all over a clean REST API.
Getting access
The developer platform is a premium capability that runs on the same billing model as the rest of AI Phone 360 — a paid subscription plus metered usage.
- A paid AI Phone 360 organization with an active subscription (BASIC, PRO, or ENTERPRISE).
- The Developer Platform add-on enabled on your organization. During the beta this is granted by our team — request access.
- A positive credit balance (the same wallet that powers your calls & texts).
Once your organization has the add-on, generate API keys from the dashboard at Settings → Developer, or via the keys API.
402 until you add funds. Webhooks that fire while you're blocked are queued and delivered once you reload (up to 30 days).
Quickstart
Every request goes to https://api.aiphone360.com/api/public/v1 and is authenticated with your API key as a Bearer token.
1. List your most recent calls
curl https://api.aiphone360.com/api/public/v1/calls?limit=5 \
-H "Authorization: Bearer aip_live_your_key_here"
2. Send a text message
curl -X POST https://api.aiphone360.com/api/public/v1/messages \
-H "Authorization: Bearer aip_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"to":"+15555550123","body":"Thanks for calling!"}'
That's it. Responses are JSON in a consistent envelope (see Errors for the shape). For TypeScript/Node, the official SDK wraps all of this with types, retries, and webhook verification.
Authentication
Authenticate every request with an API key, sent as a Bearer token:
Authorization: Bearer aip_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
(The header x-api-key: <key> is also accepted.) Keys come in two modes, distinguished by prefix:
| Prefix | Mode | Behavior |
|---|---|---|
aip_live_ | Live | Real data, real side-effects, metered & billed. |
aip_test_ | Test (sandbox) | Never bills, never sends real SMS or triggers real side-effects. See Test mode. |
Billing & credits
The platform bills like everything else in AI Phone 360: your monthly subscription is required for access, and usage is metered against your credit wallet on top of a generous monthly free quota.
| Metered action | Unit | Notes |
|---|---|---|
| API request | per 1,000 requests | Billed in 1,000-request blocks after your monthly free quota. |
| Webhook delivery | per delivery attempt | Every attempt counts (including retries) so you can rely on at-least-once delivery. |
| Custom-tool invocation | per call | Each time the AI calls one of your endpoints (voice or chat). |
| SMS sent via API | per segment | Billed through your existing SMS usage (carrier passthrough) — same rate as the app. |
Exact per-unit rates and free quotas depend on your plan and are shown on your dashboard. Everything is recorded — you (and our team) can see every billed request, webhook, and tool call, tagged by API key, in usage reporting.
aip_test_ key are counted for visibility but never charged and never debit your wallet.Scopes & keys
Each API key is granted a set of least-privilege scopes. A request to an endpoint whose scope your key lacks returns 403 INSUFFICIENT_SCOPE. Grant a key only what it needs.
| Scope | Grants |
|---|---|
| read:calls | List & read calls. |
| read:transcripts | Read call transcripts. |
| read:recordings | Read call recording URLs. |
| read:contacts | List & read contacts. |
| write:contacts | Create & update contacts. |
| write:sms | Send SMS via POST /messages. |
| read:usage | Read config & list your keys. |
| manage:config | Update AI config; create/revoke keys. |
| manage:webhooks | Manage webhook endpoints & deliveries. |
| manage:tools | Manage custom tools. |
| manage:agents | Manage specialized AI agents. |
Test mode
Use a aip_test_ key to build and test safely:
- Reads return your real data (read-only is safe).
POST /messagesreturns a synthetic success — no real SMS is sent, no carrier charge.- Webhooks & tool calls triggered in test mode are flagged and never billed.
- Test usage never debits your wallet and never blocks on balance.
Switch to a aip_live_ key when you're ready for real side-effects.
Pagination
List endpoints are cursor-paginated. Pass limit (max 100) and the cursor from the previous page's pagination.nextCursor:
let cursor;
do {
const page = await client.calls.list({ cursor, limit: 100 });
for (const call of page.data) { /* … */ }
cursor = page.pagination.nextCursor;
} while (cursor);
Errors
Every response uses a consistent envelope. Success:
{ "success": true, "data": { …payload… }, "message": "…" }
Failure carries a stable machine code and HTTP status:
{ "success": false, "error": { "message": "…", "code": "INSUFFICIENT_SCOPE", "status": 403 } }
| Code | Status | Meaning |
|---|---|---|
API_KEY_REQUIRED | 401 | No key supplied. |
INVALID_API_KEY | 401 | Key not found, revoked, or expired. |
PLATFORM_ADDON_REQUIRED | 402 | Developer add-on not enabled for this org. |
SUBSCRIPTION_REQUIRED | 402 | No active paid subscription. |
INSUFFICIENT_CREDITS | 402 | Wallet is out of credits — add funds to resume. |
INSUFFICIENT_SCOPE | 403 | Key lacks a required scope. |
BUSINESS_SUSPENDED | 403 | Organization suspended for abuse/compliance. |
RESOURCE_NOT_FOUND | 404 | The id doesn't exist (or isn't yours). |
VALIDATION_ERROR | 400 | Request body/query failed validation. |
RATE_LIMIT_EXCEEDED | 429 | Too many requests — back off (honor Retry-After). |
Rate limits
Requests are rate-limited per API key. On 429, honor the Retry-After header and back off. The official SDK retries 429 and 5xx automatically with exponential backoff.
Calls
List calls (newest first). Scope read:calls. Query: limit, cursor, direction, dateRange, search.
Full detail for one call. Scope read:calls.
The call transcript (speaker-attributed turns). Scope read:transcripts.
A recording URL (when available). Scope read:recordings.
Contacts
List contacts. Scope read:contacts. Query: limit, cursor, search.
One contact. Scope read:contacts.
Create a contact. Scope write:contacts. Body: phoneNumber (required), name, email, company.
Update a contact. Scope write:contacts.
Messages (SMS)
Send an SMS from your AI Phone 360 number. Scope write:sms. Body: to, body.
422. This is the same compliance chokepoint the app uses — it protects your number's reputation. Pass an Idempotency-Key header so retries never double-send.
AI config
Read a curated subset of your AI configuration. Scope read:usage.
Update a curated, safe subset of config (e.g. language, timezone, call-handling mode). Scope manage:config. Sensitive settings (payments, spam, PII) are never writable via the API.
Webhooks (manage)
Scope manage:webhooks for all of these. See the Receiving webhooks guide for the delivery format.
Register an endpoint. Body: url (public HTTPS), events (array). Returns a whsec_… signing secret — store it to verify deliveries.
Send a test delivery to verify your endpoint.
Inspect delivery history and replay any delivery.
API keys (manage)
List your keys (masked). Scope read:usage.
Create a key — returns the secret once. Scope manage:config. Body: name, mode (test|live), scopes.
Revoke, or rotate with a grace window so you can roll the new key out with zero downtime.
Custom tools (manage)
Scope manage:tools. See the AI calls your systems guide.
AI agents (manage)
Scope manage:agents. Define multiple specialized AI agents for one business — e.g. a billing agent that can send a payment link and collect an invoice number, and a product-support agent that collects a serial number and searches only that product's knowledge. A main greeter agent (isDefault: true) answers every call and hands off in-call to the right specialist; the caller goes AI → AI in the same call, no redial. Define no agents and your single AI agent handles everything (default).
Create body: agentKey (lowercase id, unique per business), displayName, instructions (the specialist's focused role — knowledge comes from your knowledge base via RAG, don't paste it here), matchHints[] (caller-intent phrases the greeter routes on), tools ({ useCustomToolIds[], allowPayments, allowBooking, allowTransfer, allowKnowledgeSearch } — useCustomToolIds empty = the agent may use all your custom tools), knowledgeBaseIds[] (RAG scope — empty = all business knowledge), isDefault, enabled. Tool and knowledge-base ids must belong to your business. To make an agent collect specific fields, create a data-collection field with that agent's agentId.
curl -X POST https://api.aiphone360.com/api/public/v1/agents \
-H "Authorization: Bearer aip_live_…" -H "Content-Type: application/json" \
-d '{"agentKey":"billing","displayName":"Billing","instructions":"You handle billing. Collect the invoice number and offer a secure payment link.","matchHints":["bill","invoice","refund"],"tools":{"allowPayments":true}}'
Receiving webhooks
Register an HTTPS endpoint and AI Phone 360 will POST a JSON event the instant something happens. Delivery is at-least-once — dedupe on event.id. Each event:
{
"id": "evt_…",
"type": "call.completed",
"createdAt": "2026-06-28T20:00:00Z",
"businessId": "…",
"data": { …event-specific payload… }
}
Event types
| Event | Fires when |
|---|---|
call.started | An inbound call begins. |
call.completed | A call ends & post-call processing finishes (incl. summary). |
transcript.ready | The transcript is available. |
sms.received | An inbound text arrives. |
sms.sent | An outbound text is sent. |
voicemail.created | A voicemail is recorded. |
contact.created / contact.updated | A contact is created / meaningfully changed. |
appointment.booked | An appointment is booked. |
Retries use exponential backoff; an endpoint that fails repeatedly is auto-disabled (you'll see it in delivery logs). Every delivery attempt is metered.
Verifying webhook signatures
Every delivery carries an X-AIP-Signature header: t=<unix>,v1=<hex> where v1 is HMAC-SHA256(secret, "<t>.<rawBody>"). Always verify before trusting the payload, using the whsec_ secret from when you created the endpoint. The SDK does this for you:
import { AiPhone360 } from "@aiphone360/sdk";
import express from "express";
app.post("/webhooks/aiphone", express.raw({ type: "application/json" }), (req, res) => {
try {
// Pass the RAW body bytes, not a parsed object.
AiPhone360.verifyWebhook(req.body.toString("utf8"), req.headers["x-aip-signature"], process.env.AIP_WEBHOOK_SECRET);
} catch {
return res.status(400).send("bad signature");
}
const event = JSON.parse(req.body.toString("utf8"));
// handle event.type …
res.sendStatus(200);
});
Verification rejects a timestamp older than 5 minutes to stop replay attacks. Doing it manually in another language? Recompute the HMAC over `${t}.${rawBody}` and compare in constant time.
Let the AI call your systems
Custom tools let your AI receptionist call your API live during a phone call or text — to look up an order, check availability, create a ticket, anything. You describe the tool; AI Phone 360 calls your HTTPS endpoint when the conversation needs it and relays the result back to the AI.
- Register a tool (dashboard or
POST /tools) with a name, description, JSON-schema for its inputs, your HTTPSendpointUrl, and optional auth. - During a call, the AI decides to use it and AI Phone 360
POSTs{ arguments, callSessionId, tool }to your endpoint. - Your endpoint responds with JSON within ~10 seconds; the AI uses it as data (never as instructions — results can't change call control flow).
Official SDK
The TypeScript/Node SDK wraps the API with types, automatic retries, cursor pagination, and webhook verification.
npm install @aiphone360/sdk
import { AiPhone360 } from "@aiphone360/sdk";
const client = new AiPhone360({ apiKey: process.env.AIP_KEY });
// mode is auto-detected from the key prefix (aip_test_ / aip_live_)
const { data } = await client.calls.list({ limit: 25 });
await client.sms.send({ to: "+15555550123", body: "Hi from our app" });
const contact = await client.contacts.create({ phoneNumber: "+15555550123", name: "Jordan" });
Errors throw a typed AiPhone360Error with code, status, and a requestId (give that to support). 429/5xx are retried automatically.