Skip to content
TriggersonCallHoldstable

On hold

Fires whenever a "Place caller on hold" step runs. Use it to start a wait-time timer, send a Slack ping, or kick off any side-task that should run while t…

What it does

Fires every time a Place caller on hold (holdCall) node runs. The worker has already started the hold music, marked the call as held, and written a row to the call_holds table by the time your chain runs — the trigger is a side-chain for the work that should happen alongside the hold, not for managing the hold itself.

The chain runs in an isolated state branch and shares the call's vars, so it sees vars.transferTo (set if the hold is part of a transfer flow), vars._queueName (set when the caller is being parked into a queue), and anything else the main flow has stamped. That makes it a natural fit for "the customer is now waiting" notifications, started-at timestamps you'll later read on unholdCall, or wait-time analytics.

When to use it

  • Send a Slack ping to #ops when a customer is placed on hold so the team can keep an eye on long waits.
  • Stamp vars.heldAt with the current timestamp, then read it after unholdCall to compute hold duration.
  • Fire an HTTP webhook to your own dashboard so the live agent view can highlight calls currently parked.
  • Increment a counter in your CRM tracking how many holds happen per customer per day.

If you need to play music or audio during the hold, that's already handled by the holdCall node's own configuration — pass a holdMusicUrl there instead of trying to start audio from this trigger.

Configuration

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

Fires whenever a "Place caller on hold" step runs. Use it to start a wait-time timer, send a Slack ping, or kick off any side-task that should run while the caller is on hold.

FieldLabelTypeRequiredDefaultNotes
_labelTrigger labeltextOptional
_noteInternal notetextareaOptional

Outgoing events: triggered

Examples

Slack ping when a customer goes on hold

{
  "id": "hold-trigger",
  "type": "onCallHold",
  "config": { "_label": "Notify ops on hold" },
  "on": { "triggered": "slack-ping" }
}
[onCallHold] ──► [httpCall POST hooks.slack.com/...
                   body: { text: "Caller {{event.from}} is on hold" }] ──► [end]

The main flow runs holdCall to actually park the caller; this trigger fires alongside it.

[holdCall holdMusicUrl=...] ──► [enqueue queue=support] ──► ...
       │
       └──► (onCallHold trigger fires here, in parallel)

Gotchas

  • Fires only via holdCall, not on every Telnyx hold event. If the caller's leg goes on hold for some other reason (carrier-side hold, unholdCall -> holdCall cycles from a parallel sub-flow), this trigger may not fire. Wire it to holdCall semantics, not "any hold".
  • The hold is already in progress when the trigger runs. The playbackStart for the hold music and the call_holds insert both happen before runTriggerChains('onCallHold') is called. Don't try to stop or modify the hold from inside the chain — use a separate unholdCall node from the main flow if you need to lift it.
  • 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 true by the worker before the chain runs, and back to false by unholdCall.
  • Reason inference is implicit. The hold reason written to call_holds.reason is determined by the worker: "transfer" if vars.transferTo is set, "queue" if vars._queueName is set, else "manual". Your chain can read these flags off vars to branch on why the hold happened.