Voicemail ships behind a per-environment flag. Until it is enabled for your
account every endpoint returns
503 VOICEMAIL_DISABLED.Arm a number
PUT /v1/numbers/{id}/voicemail turns voicemail on or off for one of your Wave
numbers. Needs the voicemail:write scope.
A custom greeting
By default Wave plays a standard greeting. To play your own, first upload a WAV withPOST /v1/callflows/audio — that returns an audio_ref — then
set it as greeting_ref:
greeting_ref must be a prompt your organization uploaded — an arbitrary URL
returns 400 VOICEMAIL_GREETING_INVALID. Send null to clear it back to the
default; omit the key to leave the current greeting unchanged.
List the box
GET /v1/voicemails returns your messages newest-first with cursor pagination.
Needs the voicemail:read scope.
next_cursor back as ?cursor= to page. Narrow the list with ?number= (one
number’s box) and ?listened=true|false (heard vs new). Fetch one message with
GET /v1/voicemails/{id}.
Two fields are reserved for later additions:
transcription_status is pending
for now (automatic transcription comes later, and transcription_text stays
null until then), and duration_seconds is null until the telephony engine
reports a message length.Play a message
GET /v1/voicemails/{id}/recording-url returns a time-limited playback URL
(valid ~60 minutes). Needs the voicemail:read scope and a production key.
404 VOICEMAIL_RECORDING_NOT_FOUND or
503 VOICEMAIL_SERVICE_UNAVAILABLE. Sandbox keys get 400 SANDBOX_KEY_NOT_ALLOWED.
Mark heard, and delete
POST /v1/voicemails/{id}/listened stamps the message as heard (the first time
only, so the “first heard” instant is stable). DELETE /v1/voicemails/{id}
soft-deletes it and clears its recording. Both need the voicemail:write scope.
Get notified
Instead of polling the box, subscribe to thevoicemail.received webhook
— Wave posts it once a new message’s recording is ready:
Next steps
WaveML
The
<Play> and <Record> verbs behind the voicemail flow.Webhooks
Get
voicemail.received pushed to you instead of polling.
