Overview
What this module covers, the edit-only surface, materialization on first open, and the response envelope.
What this reference explains
This module covers phone numbers end to end on the panel API: search purchasable inventory, purchase an unassigned number, list numbers (including unassigned), retrieve configuration, and update inbound routing / fallback / webhook / SMS. Release is not covered here.
Assistant create flows may still purchase and attach a number at create time when one is provided; purchasing here is the two-step path when you buy first and assign later.
Two-step purchase
- Step 1 — purchase.
GET /phone-numbers/availablesearches inventory;POST /phone-numberspurchases and registers the number with no inbound target (assistant / squad / workflow all null). - Step 2 — assign.
PUT /phone-numbers/{id}sets exactly one ofvapi_assistant_id,vapi_squad_id, orvapi_workflow_id. - List rows include an
unassignedboolean when no inbound target is set.
List & materialise
- List rows are summaries. They are built from assistants that currently carry a number, unioned with any configuration rows that already exist (including unassigned purchases and squad- or workflow-routed numbers). A row's
idmay benulluntil that number has been opened for editing at least once — except numbers created viaPOST /phone-numbers, which already have a configuration row. - Opening a number materialises it. Retrieving a number that only exists on an assistant creates its local configuration row by reading the live voice platform. Every retrieval after that reuses the stored row.
Clearing semantics
On update, server and fallback_destination distinguish "absent" from "present but empty": omitting the key entirely leaves the block untouched, while sending it as null or {} explicitly clears the whole block. A non-empty object merges onto the current value, so a partial update (for example just {"credentialId": ""}) does not wipe out an existing url or headers.
Inbound routing is exclusive
A number routes inbound calls to exactly one target: an assistant (vapi_assistant_id), a squad (vapi_squad_id), or a workflow (vapi_workflow_id). Setting more than one of these in the same request is rejected before anything is written. Setting one of them clears the other two, both locally and on the live platform.
Identifiers
The {id} path parameter accepts the number's digits (E.164 without the leading +) or its full E.164 form (with +); once a configuration row exists, its numeric row id also resolves. There is no separate public UUID for a phone-number configuration — the phone number itself is the primary lookup key.
Response envelope
The panel envelope. sms_available (whether the SMS toggle is meaningful for this number's provider) is computed and attached only on the retrieve endpoint, not on update. The retrieve and update endpoints may also carry an internal mirror of the live platform's own phone-number resource; it is not part of the documented contract and is omitted from the examples on this page.
Feature availability
This module is gated by the phone_numbers feature. When disabled, every endpoint under /phone-numbers returns 403 with {"message":"This feature is not enabled for your account. Please contact your administrator.","feature":"phone_numbers"}.