Phone, SMS & voice

Voice calls

Route inbound calls to a phone, a SIP address or an AI agent, add voicemail, business hours and an IVR menu, and place, transfer and end outbound calls.

Every Pozy number takes and makes regular phone calls as soon as it is active. Inbound calls go wherever you point them: a mobile, a SIP endpoint, or an AI voice agent. Outbound calls dial from your number with one request. Every call, in either direction, lands in one call history.

Calls are billed per connected minute by destination. Unanswered, busy and failed calls are not charged.

Note

These are phone network calls. Voice calls inside a WhatsApp chat are a separate feature: see WhatsApp calling. Both appear in the same history.

#Route inbound calls

All inbound settings live on one idempotent endpoint, POST /v1/phone-numbers/{id}/voice. It writes only the fields you send, so you can call it again later to change one setting.

curl -X POST https://api.pozy.ai/v1/phone-numbers/6650d2e1b3c4d5e6f7081923/voice \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "forwardTo": "tel:+13125550188",
    "forwardCallerId": "caller",
    "voicemailEnabled": true,
    "voicemailGreeting": "You have reached Acme. Leave a message and we will call you back."
  }'

The response is the full effective configuration (pstnForwardTo, voicemail, hours, IVR, blocklist, recording settings).

#Destinations

forwardTo Sends the call to
tel:+13125550188 A phone number
sip:agent@pbx.example.com A SIP endpoint or a hosted voice agent
wss://agent.example.com/media Your own media server, for a custom AI agent

Leave forwardTo out to keep the current destination. An empty string clears it, which leaves the number able to call out but not to ring anywhere on inbound.

#Inbound features

Feature Fields Behaviour
Voicemail voicemailEnabled, voicemailGreeting On by default. Catches unanswered calls (about 25 seconds of ringing), failed bridges and after-hours calls. Records up to 2 minutes.
Business hours businessHoursEnabled, businessHoursTimezone, businessHours Rings only inside the windows. Outside them the call goes to voicemail.
IVR menu ivrEnabled, ivrPrompt, ivrOptions Plays a menu and routes by keypress. Replaces the plain forward.
Blocklist blockedCallers Rejects listed numbers with a busy signal. Each write replaces the whole list.
Caller ID forwardCallerId Show your number (business, default) or the original caller (caller) on the forwarded leg
Recording recordingEnabled Off by default. A consent notice plays first.
Transcription transcriptionEnabled, transcriptionLanguage Off by default. Language auto, en or es.

Business hours and the IVR menu take structured values:

Hours and a menu
{
  "businessHoursEnabled": true,
  "businessHoursTimezone": "Europe/Madrid",
  "businessHours": [
    { "day": 1, "open": "09:00", "close": "18:00" },
    { "day": 2, "open": "09:00", "close": "18:00" },
    { "day": 6, "open": "10:00", "close": "14:00" }
  ],
  "ivrEnabled": true,
  "ivrPrompt": "Press 1 for sales, 2 for support, 3 to talk to our assistant.",
  "ivrOptions": [
    { "digit": "1", "forwardTo": "tel:+13125550188", "label": "Sales" },
    { "digit": "2", "forwardTo": "sip:support@pbx.example.com", "label": "Support" },
    { "digit": "3", "forwardTo": "wss://agent.example.com/media", "label": "Assistant" }
  ]
}
  • A window has day (0 is Sunday through 6), open and close as HH:MM in the timezone. A day with no window is closed. A window whose close is before its open runs past midnight. Up to 21 windows.
  • A menu option has a digit (0 to 9, * or #), its own forwardTo and an optional label. Up to 12 options. No input or an unknown digit ends the call.

#The order an inbound call follows

  1. Blocklist. A blocked caller gets a busy signal before the call is answered: no charge, no voicemail, no webhook.
  2. call.received fires.
  3. Business hours. Outside the windows, the call goes straight to voicemail (or hangs up if voicemail is off).
  4. IVR menu, if on. The digit picks a destination.
  5. Ring the destination. If nobody answers or the bridge fails, voicemail takes the call.
  6. call.ended (or call.failed on a hard error).

Voicemail sends the account an email. The recording, and the transcript when transcription is on, attach to the call record. There is no separate voicemail webhook: call.ended carries isVoicemail: true.

#Turn calling off

DELETE /v1/phone-numbers/{id}/voice disables calls on the number. Pozy keeps the settings, so enabling again restores them.

#Place an outbound call

POST /v1/voice/calls with to. When the callee answers, Pozy bridges them to the number's forward destination, or to a per-call forwardTo. An optional greeting is spoken to the callee first.

curl -X POST https://api.pozy.ai/v1/voice/calls \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Idempotency-Key: callback-ticket-5521" \
  -H "Content-Type: application/json" \
  -d '{
    "fromNumber": "+14155550142",
    "to": "+13125550188",
    "forwardTo": "tel:+14155550100",
    "greeting": "Hi, this is Acme returning your call. Connecting you now."
  }'

A 200 means the call is dialing. Everything after that is asynchronous: follow it with GET /v1/voice/calls/{id}, or with call.ended and call.failed. Outbound phone calls do not send call.received.

Field What it does
to Number to call (required)
fromNumber Which of your numbers to call from. Optional when you own exactly one voice-enabled number.
forwardTo Who the callee is bridged to: tel:, sip: or wss:// (an AI agent)
greeting Spoken to the callee before the bridge, up to 1,000 characters
amd Answering-machine detection. The bridge waits until Pozy knows whether a person answered.
voicemailDropMessage With amd, speak this to an answering machine and hang up
recordOverride, transcribeOverride, transcriptionLanguage Override the number's defaults for this call
ringTimeoutSeconds How long to ring. Default 30, up to 120.

Send an Idempotency-Key so a retry does not dial (and bill) a second call.

#Estimate the cost first

GET /v1/voice/calls/estimate?to=%2B13125550188&minutes=5&recording=true returns perMinuteUsd and a breakdown whose billableCostUSD is what you will be charged, using the same formula as the invoice. Use it to show prices to your users or to block expensive routes. Estimates cover outbound destinations only.

#Transfer and hang up

  • POST /v1/voice/calls/{id}/transfer with to (a +E164 number or a sip: URI) hands a live call to someone else. The new leg always shows your number. wss:// is not a valid transfer target.
  • POST /v1/voice/calls/{id}/end hangs up. It is safe to repeat: ending a finished call returns 200 with its current status. It also ends WhatsApp calls.

Final duration and cost are written when the hangup lands, so a call record can show its previous status for a moment.

#Webhook events

Call Events, in order
Inbound call.received at ring time, then call.ended or call.failed
Outbound phone call (API or browser) call.ended or call.failed only

call.ended carries durationSeconds, endReason (hangup, no_answer, rejected or error), isVoicemail, callErrors, a cost breakdown in billing, and a signed recordingUrl when recording was on. Unanswered, busy and rejected calls end with call.ended, so branch on endReason. call.failed is for hard errors before or during the bridge.

Missed-call text-back

On an inbound call.ended with endReason: "no_answer", text the caller back: send an SMS from call.to (your number) to call.from. The caller gets an answer even when nobody picked up. call.received also carries a conversationId if you would rather reply in the existing inbox thread.

Event When it fires
call.received Call received.
call.ended Call ended.
call.failed Call failed.
call.permission_request Call permission request reply.

#Limits

Limit Value
Outbound calls 60 per rolling hour across all numbers on the key. Past it, 429.
Business hours 21 windows
IVR options 12
Ringing before voicemail About 25 seconds
Voicemail message 2 minutes
Emergency calls Not supported

#Errors

Status Code Cause Fix
422 No voice-enabled number matches fromNumber, or the number has no destination and the call sent no forwardTo Set forwardTo on the number or the call
409 Transfer on a call that is not connected yet or already ended Transfer only while live
409 invalid_resource_state The number is attached to a SIP trunk, which owns its calls Detach it first
422 The number is a WhatsApp number on your own carrier, so Pozy cannot route its calls Use a number bought or ported into Pozy
429 Outbound cap reached Wait for the rolling hour
502 The carrier refused to place the call. It is marked failed. Retry

#Endpoints

Endpoint What it does
POST /v1/phone-numbers/{id}/voice Enable phone calling on a number
DELETE /v1/phone-numbers/{id}/voice Disable phone calling on a number
POST /v1/voice/calls Place an outbound phone call
GET /v1/voice/calls/estimate Estimate call cost
GET /v1/voice/calls List phone calls
GET /v1/voice/calls/{id} Get a phone call
POST /v1/voice/calls/{id}/transfer Blind-transfer a live call
POST /v1/voice/calls/{id}/end Hang up a live call