Static Media & Call Flow
Play recorded announcements before, after, or instead of the AI conversation — and get evidence of exactly what played.
Overview
Two fields in VoiceElements_Instructions work together:
mediaCatalog
Declares the media items this call may use, each identified by a stable mediaReference.
callFlow
An ordered list of steps that play media, run the Realtime AI session, or end the call.
The same mediaCatalog references are used by attended-transfer hold media
and caller comfort audio.
It is also the concept behind the VnsPortal Media Library: a managed AI Voice Agent maps Media Library files to these references for you.
callFlow keeps the legacy behavior: a single Realtime session with no announcements.
mediaCatalog
Each item names one piece of WAV audio. Where the audio comes from depends on which source fields you set:
{
"VoiceElements_Instructions": {
"mediaCatalog": [
{ "mediaReference": "ReceptionHold" },
{
"mediaReference": "RecordingConsent",
"httpsSource": "https://media.example.com/prompts/recording-consent.wav",
"httpsHeaders": {
"Token": "<<vns-api-token:MediaHost>>"
}
},
{
"mediaReference": "ShortChime",
"inlineWaveBase64": "<base64-encoded WAV file>"
}
]
}
}
| Field | Description |
|---|---|
| mediaReference | Required. The item's identity. Case-insensitive, compared after trimming. An item with only a mediaReference resolves to your account's VNS-hosted Media Library mapping. |
| inlineWaveBase64 | Optional per-session WAV source, Base64-encoded in the CallStart response. |
| httpsSource | Optional HTTPS URL of a WAV file. |
| httpsHeaders | Valid only with httpsSource. Currently permits one Token header whose value is a VNS token-profile placeholder. |
- •
inlineWaveBase64andhttpsSourceare mutually exclusive. - •Secrets, Base64 content, URLs, headers, and local paths are never returned in CallEnd diagnostics.
callFlow
Each step is an object. Enum values are JSON strings, not integers.
| Field | Values / Description |
|---|---|
| sequence | Step order. |
| label | Short name for the step. |
| description | Optional notes for people reading the configuration. |
| operation | PlayMedia, RunRealtime, or EndCall. |
| mediaReference | The mediaCatalog item to play (for PlayMedia). |
| interruptDigits | String of DTMF digits that let the caller interrupt playback ("" in the runtime's example). |
| resolutionFailureMode | Continue — skip the step if its media can't be resolved; AbortBeforeDial — don't place the call. |
| recordingFailurePolicy | onResolutionFailure and onPlaybackFailure, each NoChange or DisableAndDiscard. Use DisableAndDiscard when a step is a recording-consent notice. |
| callEndEvidence | None, FailuresOnly, or Full — how much of this step is reported in CallEnd mediaEvidence. |
| condition | Always or IdleStrikeLimitReached (run only when the caller stopped responding and the idle limit was reached). |
Flow Rules
A null or empty callFlow preserves the legacy single-Realtime-session behavior.
At most one RunRealtime step is allowed.
EndCall must be the final step.
A flow without RunRealtime must end with EndCall.
Examples
Inbound recording-consent announcement
Plays a consent notice before the AI answers. If the notice can't be resolved or played, the recording is disabled and discarded rather than recording a caller who never heard it.
{
"VoiceElements_Instructions": {
"recordCall": true,
"mediaCatalog": [
{ "mediaReference": "RecordingConsent" }
],
"callFlow": [
{
"sequence": 1,
"label": "Consent notice",
"description": "Tell the caller the call is recorded before the AI answers.",
"operation": "PlayMedia",
"mediaReference": "RecordingConsent",
"resolutionFailureMode": "Continue",
"recordingFailurePolicy": {
"onResolutionFailure": "DisableAndDiscard",
"onPlaybackFailure": "DisableAndDiscard"
},
"callEndEvidence": "FailuresOnly",
"condition": "Always"
},
{
"sequence": 2,
"label": "AI agent",
"operation": "RunRealtime",
"condition": "Always"
}
]
}
}
Outbound announcement
Identifies the business before the AI speaks. AbortBeforeDial means VNS won't place the call at all if the introduction can't be resolved.
{
"VoiceElements_Instructions": {
"mediaCatalog": [
{ "mediaReference": "OutboundIntro" }
],
"callFlow": [
{
"sequence": 1,
"label": "Outbound introduction",
"description": "Identify the business before the AI starts talking.",
"operation": "PlayMedia",
"mediaReference": "OutboundIntro",
"resolutionFailureMode": "AbortBeforeDial",
"callEndEvidence": "Full",
"condition": "Always"
},
{
"sequence": 2,
"label": "AI agent",
"operation": "RunRealtime",
"condition": "Always"
}
]
}
}
Idle farewell
The farewell step runs only when the Realtime session ended because the caller stopped responding (see maxIdleStrikes in the field reference).
{
"VoiceElements_Instructions": {
"mediaCatalog": [
{ "mediaReference": "IdleGoodbye" }
],
"callFlow": [
{
"sequence": 1,
"label": "AI agent",
"operation": "RunRealtime",
"condition": "Always"
},
{
"sequence": 2,
"label": "Idle farewell",
"description": "Only plays when the caller stopped responding.",
"operation": "PlayMedia",
"mediaReference": "IdleGoodbye",
"resolutionFailureMode": "Continue",
"callEndEvidence": "FailuresOnly",
"condition": "IdleStrikeLimitReached"
},
{
"sequence": 3,
"label": "Hang up",
"operation": "EndCall",
"condition": "Always"
}
]
}
}
Announcement only
No AI at all — play a message and hang up. Because there's no RunRealtime step, the flow must end with EndCall.
{
"VoiceElements_Instructions": {
"mediaCatalog": [
{ "mediaReference": "HolidayClosureNotice" }
],
"callFlow": [
{
"sequence": 1,
"label": "Closure notice",
"operation": "PlayMedia",
"mediaReference": "HolidayClosureNotice",
"resolutionFailureMode": "Continue",
"callEndEvidence": "Full",
"condition": "Always"
},
{
"sequence": 2,
"label": "Hang up",
"operation": "EndCall",
"condition": "Always"
}
]
}
}
CallEnd Evidence
The CallEnd webhook reports what happened with three fields:
| mediaEvidence | Array with one entry per reported media step, filtered by each step's callEndEvidence setting. Never includes paths, URLs, Base64, headers, or secrets. |
| realtimeExitReason | Why the Realtime AI session ended (for example "Completed"). |
| callFlowFailureCode | Sanitized failure code when a call-flow step could not complete. |
Ready to Automate Your Phone Lines?
Create your account in VnsPortal and set up your first agent from a template today — or book a live demo and we'll walk you through it.
Questions first? Contact sales