On unhold
Fires when an agent takes the caller off hold. Use it to log the hold to a CRM or kick off any side-task that should run when a held caller is brought bac…
What it does
Fires when an agent takes the caller off hold from their softphone.
There is no unholdCall flow node anymore — like the hold itself, resuming
is something an agent does mid-call. The moment it happens, the caller's own
active flow's onCallUnhold chain runs.
Unlike onCallHold, this chain's verbs are not played into the live
conference — there's no wire-level "unhold" audio event to hang them off of,
so say / playAudio output from this chain is informational only (the
caller doesn't hear it). What matters is the chain running at all: its
side-effects (a screenPop refresh, an agentNotify, a setVar, an
analytics webhook) fire the instant the resume happens.
When to use it
- Send a Slack ping to
#opswhen a long-held customer is finally picked back up - Compute hold duration by reading a
vars.heldAtstamped fromonCallHoldand postingnow - vars.heldAtto your dashboard - Refresh a screen pop or CRM note the moment the agent comes back
- Increment a counter tracking how many holds happen per customer per day
If you need the caller to actually hear something the moment they're
picked back up ("Thanks for waiting"), wire that into the main flow itself
(a say after wherever the bridge resumes) — this trigger's own audio
output is discarded.
Configuration
_label and _note are author-only metadata; this trigger has no runtime
configuration of its own.
Fires when an agent takes the caller off hold. Use it to log the hold to a CRM or kick off any side-task that should run when a held caller is brought back.
| Field | Label | Type | Required | Default | Notes |
|---|---|---|---|---|---|
| _label | Trigger label | text | Optional | — | |
| _note | Internal note | textarea | Optional | — |
Outgoing events: triggered
Examples
Slack ping when a customer comes off hold
{
"id": "unhold-trigger",
"type": "onCallUnhold",
"config": { "_label": "Notify ops on resume" },
"on": { "triggered": "slack-ping" }
}
[onCallUnhold] ──► [apiCall POST hooks.slack.com/...
body: { text: "Caller {{event.from}} resumed" }] ──► [end]
Compute and log hold duration
Pairs with a setVar in the onCallHold chain that stamps vars.heldAt.
{
"id": "unhold-trigger",
"type": "onCallUnhold",
"config": {},
"on": { "triggered": "log-duration" }
}
{
"id": "log-duration",
"type": "apiCall",
"config": {
"mode": "http",
"url": "https://analytics.example.com/hold-duration",
"method": "POST",
"body": "{ \"heldAt\": \"{{vars.heldAt}}\" }"
},
"on": { "next": "end" }
}
Gotchas
- Fires from the softphone, not from a flow node. There is no
unholdCallnode anymore — an agent takes the caller off hold from their softphone UI, and that's what triggers this chain. - The chain's audio output is discarded.
say/playAudioverbs from this chain don't reach the live call — there's no unhold wire event to play them into. Use this trigger for side-effects only; put an audible "thanks for waiting" in the main flow if you need one. - Side-chain runs in an isolated state branch. It shares the call's
varsbut can't move the main flow's cursor. - Caller-initiated hangup during hold won't fire this. If the caller hangs up while on hold, the hold simply ends with the call — no agent resumed it, so this trigger never runs.
- Implemented by
GET|POST /hooks/conf-unholdinrust/bins/heyquad-walker/src/webhooks.rs, called byheyquad-apithe moment an agent resumes a held caller.
