Skip to content
TriggersonCallUnholdstable

On unhold

Fires whenever a "Resume caller from hold" step runs. Use it to stop a wait-time timer, log the hold duration to a CRM, or kick off any side-task that sho…

What it does

Fires every time a Resume caller from hold (unholdCall) node runs. The worker has already stopped the hold music, closed the open row in the call_holds table (stamping endedAt and computing durationSecs), and flipped vars._onHold back to false by the time your chain runs — the trigger is a side-chain for the work that should happen alongside the resume, not for managing the unhold itself.

The chain runs in an isolated state branch and shares the call's vars, so it sees anything the main flow stamped during the hold (for example vars.heldAt if you set a started-at timestamp from onCallHold). That makes it a natural fit for "the customer is back" notifications, hold duration analytics, or CRM updates that should land the moment the caller is brought back.

When to use it

  • Send a Slack ping to #ops when a long-held customer is finally picked back up so the team can stand down.
  • Compute hold duration by reading a vars.heldAt stamped from onCallHold and posting now - vars.heldAt to your dashboard.
  • Fire an HTTP webhook to your own analytics so the live agent view can clear the "currently parked" highlight.
  • Increment a counter in your CRM tracking how many resume events happen per customer per day.

If you need to play a "thanks for waiting" prompt after the resume, that's better wired into the main flow as a say or playAudio after the unholdCall node, so it cleanly gates forward progress instead of racing against the side-chain.

Configuration

_label and _note are author-only metadata; this trigger has no runtime configuration of its own.

Fires whenever a "Resume caller from hold" step runs. Use it to stop a wait-time timer, log the hold duration to a CRM, or kick off any side-task that should run when a held caller is brought back.

FieldLabelTypeRequiredDefaultNotes
_labelTrigger labeltextOptional
_noteInternal notetextareaOptional

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] ──► [httpCall POST hooks.slack.com/...
                     body: { text: "Caller {{event.from}} resumed" }] ──► [end]

The main flow runs unholdCall to actually resume the caller; this trigger fires alongside it.

[unholdCall] ──► [bridge agent=...] ──► ...
       │
       └──► (onCallUnhold trigger fires here, in parallel)

Gotchas

  • Fires only via unholdCall, not on every Telnyx unhold event. If the caller's leg comes off hold for some other reason (carrier-side resume, hangup-during-hold cleanup), this trigger may not fire. Wire it to unholdCall semantics, not "any unhold".
  • The resume is already in progress when the trigger runs. The playbackStop and the call_holds close both happen before runTriggerChains('onCallUnhold') is called. Don't try to re-hold or modify playback from inside the chain — use a fresh holdCall node from the main flow if you need to park the caller again.
  • Side-chain runs in an isolated state branch. Shares vars with the main flow, but cannot move the flow position. vars._onHold is set to false by the worker before the chain runs.
  • No unholdCall upstream is fine. If unholdCall runs without a matching open hold row (the caller wasn't actually on hold), the close is a no-op but this trigger still fires. Guard inside the chain if you only want to act on real resumes.
  • Caller-initiated hangup during hold won't fire this. If the caller hangs up while on hold, the worker's hangup path closes the open hold row directly — unholdCall never runs, so neither does this trigger. Use onCallEnd for that case.