Vapi
Vapi is an outbound AI-calling platform with native voicemail detection — the reason CenterLeap evaluates it against the Bland/Telnyx-bridge stack. It dials over our own Telnyx trunk (BYOC), so calls still show our number, and Vapi handles human-vs-machine classification and the after-beep message deposit itself.
On this page
Why Vapi
Carrier answering-machine detection (beep-only) is roughly a coin flip in production. Vapi runs a dedicated detection layer (audio + timing classification) and, on voicemail, waits for the beep before delivering a pre-recorded or spoken message — the “classify fast, then wait for the beep” architecture that reliable outbound systems use.
1. Get API keys
From the Vapi dashboard → API Keys, copy the private key. Send it as Authorization: Bearer <key> on server-side requests only. The public key is for the browser Web SDK and is not used here. Base URL is https://api.vapi.ai (EU orgs: https://api.eu.vapi.ai).
2. Prepare Telnyx
On the Telnyx SIP connection that owns your caller-ID number, either allowlist Vapi's SBC IPs (IP-auth) or set credential auth and note the SIP username/password. Confirm the number is on a connection Vapi can originate from — otherwise trunk registration fails.
3. Register the BYOC trunk + number
CenterLeap exposes a one-time setup route that registers the Telnyx SIP trunk as a Vapi byo-sip-trunk credential and binds your number as a byo-phone-number. It returns the phone_number_id that becomes the outbound caller ID.
curl -s -X POST https://app.centerleap.com/api/vapi/setup \
-H "Cookie: <owner/admin session>"
# → { "phone_number_id": "pn_xxx", "credential_id": "...", "status": "active" }Gateways are created with inboundEnabled: false for an outbound-only trunk (leaving it true is a documented cause of gateway failures). Put the returned phone_number_id in VAPI_PHONE_NUMBER_ID.
4. Webhook secret
Vapi authenticates webhook deliveries with a shared secret it sends in the X-Vapi-Secret header. In the Vapi dashboard create a Bearer-token custom credential with header name X-Vapi-Secret and the Bearer prefix disabled, then set the same value in CenterLeap as VAPI_WEBHOOK_SECRET. CenterLeap does a constant-time compare on every webhook and tool call.
5. Voicemail detection
The assistant carries a voicemailDetection object and a voicemailMessage. Recommended:
{
"provider": "vapi",
"backoffPlan": { "startAtSeconds": 2, "frequencySeconds": 2.5, "maxRetries": 5 },
"beepMaxAwaitSeconds": 12
}On voicemail, Vapi waits up to beepMaxAwaitSeconds for the beep, then delivers voicemailMessage (plain text for TTS, or a URL to a pre-recorded .wav/.mp3). The call ends with endedReason: "voicemail", which CenterLeap sees on the end-of-call-report webhook.
6. Configure CenterLeap
| VAPI_PRIVATE_API_KEY | Vapi private key (server only). |
| VAPI_PHONE_NUMBER_ID | byo-phone-number id from /api/vapi/setup. |
| VAPI_SARA_VOICE_ID | 11labs voiceId for the agent. |
| VAPI_WEBHOOK_SECRET | Shared secret sent as X-Vapi-Secret. |
| VAPI_WEBHOOK_BASE_URL | Public base URL for webhooks. |
| VAPI_TELNYX_SIP_USERNAME / _PASSWORD | Setup only — omit for IP-auth trunks. |
| VAPI_TELNYX_GATEWAY_IPS | Comma-separated Telnyx SIP gateways. |
| VAPI_CALLER_E164 | The number to register as caller ID. |
7. Place a test call
curl -s -X POST https://app.centerleap.com/api/vapi/calls \
-H "Content-Type: application/json" \
-H "Cookie: <owner/admin session>" \
-d '{ "to_e164": "+1XXXXXXXXXX", "name": "Test" }'
# → { "call_id": "...", "status": "queued" }Let it reach voicemail on the test, then confirm the end-of-call-report webhook logs endedReason: voicemail and the message landed cleanly after the beep — the head-to-head against the bridge stack.