Play music
Plays hold/wait music to the caller — pick a track from the Prompts & music library (the system library or your own). Built for hold experiences: start at…
What it does
Plays hold/wait music to the caller. The track comes from the Prompts & music library — a system track or music your team uploaded. Unlike Play audio (a plain looped clip) it's built for hold experiences:
- Start at an offset (seconds) into the track.
- Play for a set number of seconds, then continue down the Finished playing path. Leave it blank to play the track once through.
- Optionally let the caller press a key to skip, which routes a Key pressed branch.
- Save the stop position to a variable so a later Play music step can pick up right where the caller left off.
When to use it
- A resumable music bed split across several steps — save the offset on one step, feed it into Start at on the next to resume seamlessly.
- Timed hold music: "play 30 seconds, then re-check the queue."
- A "press any key to skip the intro" experience before a menu.
For a one-off clip or a simple Forever loop, use Play audio. For a
spoken prompt or TTS, use Play prompt or audio (say).
Configuration
Plays hold/wait music to the caller — pick a track from the Prompts & music library (the system library or your own). Built for hold experiences: start at an offset, play for a set number of seconds, and optionally let the caller press a key to skip ahead. Save the stop position to a variable and feed it back into "Start at" on a later Play music step to pick up right where the caller left off. (To loop a clip or play a one-off one, use "Play audio"; for spoken prompts or TTS, use "Play prompt or audio".)
| Field | Label | Type | Required | Default | Notes |
|---|---|---|---|---|---|
| music | Music | audio | Required | — | Pick a music track from the Prompts & music library: a system track or one your team uploaded. A {{config.x}} / {{vars.x}} template that holds a library reference also works. |
| offsetSecs | Start at (seconds) | number | Optional | 0 | Where in the track to begin. Accepts a {{vars.x}} template so you can resume from a saved stop position. If it lands past the end of the track, playback restarts from the beginning. |
| playSecs | Play for (seconds) | number | Optional | 30 | How long to play before the flow moves on down the "Finished playing" path. Leave blank to play the track once through to the end. |
| interruptOnDtmf | Let the caller press a key to skip | boolean | Optional | false | When on, a keypad press during playback stops the music and routes the "Key pressed" branch. When off, keypresses are ignored and the music plays until the play time elapses (or the call is bridged / hangs up). |
| validDigits | Keys that interrupt | text | Optional | 1234567890*# | Which keys are allowed to interrupt. Leave blank to accept any key. Only used when "Let the caller press a key to skip" is on. |
| saveOffsetVar | Save stop position to variable | text | Optional | musicPos | Optional. When this step ends — whether the play time elapsed or the caller pressed a key — the seconds-offset where playback stopped is written to this variable. Reference it later as {{vars.musicPos}} and drop it into "Start at" on another Play music step to resume. |
Outgoing events: call.playback.ended, call.playback.dtmf, call.hangup
Examples
System hold music for 30 seconds
{
"id": "hold-music",
"type": "playMusic",
"config": { "music": "sys:music/default-hold", "playSecs": 30 },
"on": { "call.playback.ended": "check-queue", "call.hangup": "end" }
}
Resume where the caller left off
Two steps that share a position variable. The first plays 20s from the
start and saves the stop offset to musicPos; the second resumes from
there. {{vars.musicPos}} resolves before playback.
[
{
"id": "music-a",
"type": "playMusic",
"config": { "music": "sys:music/default-hold", "offsetSecs": 0, "playSecs": 20, "saveOffsetVar": "musicPos" },
"on": { "call.playback.ended": "announce" }
},
{
"id": "music-b",
"type": "playMusic",
"config": { "music": "sys:music/default-hold", "offsetSecs": "{{vars.musicPos}}", "playSecs": 20, "saveOffsetVar": "musicPos" },
"on": { "call.playback.ended": "menu" }
}
]
Press a key to skip the intro
With Let the caller press a key to skip on, a keypress stops the music and
routes the Key pressed branch (call.playback.dtmf); otherwise it plays
to the play-time and routes Finished playing (call.playback.ended). The
key the caller pressed is available downstream as {{vars.gatheredDigits}}.
{
"id": "intro",
"type": "playMusic",
"config": { "music": "sys:music/default-hold", "playSecs": 15, "interruptOnDtmf": true },
"on": { "call.playback.dtmf": "menu", "call.playback.ended": "menu", "call.hangup": "end" }
}
Gotchas
- Offsets are tracked in seconds. Every library track plays as 8 kHz mono, so the seconds ↔ samples conversion is exact.
- Offset wrap works for every library track. "If Start at is past the end of the track, start from the beginning" uses the track length the library records for each track.
- The saved offset on a key-press is an estimate. When key-interrupt is on, the platform reports which key was pressed but not where playback stopped, so the saved position is derived from elapsed time (accurate to within processing latency). The Finished playing path and the no-interrupt path save an exact position.
- "Play for" longer than the track plays once to the end. There's no auto-loop for the timing fields — a 30s play time on a 20s clip plays 20s. To loop a clip, use Play audio with a loop count.
- Key-interrupt off means keys are ignored. The music plays until the play-time elapses, the call is bridged (an agent answers), or the caller hangs up.
musicis a library reference, never a URL. It holdsasset:<uuid>,sys:music/<slug>or a{{…}}template that renders to one. A raw URL fails publish validation. If the track was deleted or disabled, the call hears the org's default hold music, then the system default.
