Skip to main content

Handover Actions

Handover actions transfer the conversation to a human agent. The same handover configuration is also used when a supervisor triggers a takeover via Listen & intervene.

The sections below describe handovers on voice and chat agents. Email agents use a queue-only form, described in Email agents (Dixa inboxes).

Type​

Choose the handover method:

  • Phone: Transfer to a specific phone number
  • Queue: Transfer to a queue in your contact center system (e.g., a Genesys queue)
  • SIP: Transfer via a SIP URI

Queue routing​

The most common approach is to define the queue ID in the Parameters Schema rather than hardcoding it in the action itself. This lets a single handover action cover multiple queues — the agent decides which queue to route to based on the conversation, and passes the queue ID when calling the action.

Parameters Schema example (multiple queues, one action):

{
"type": "object",
"properties": {
"queue_id": {
"type": "string",
"enum": ["sales", "support", "billing"],
"description": "Destination queue: sales for purchases and upgrades, support for technical issues, or billing for payments and invoices"
}
},
"required": ["queue_id"]
}

Set a fallback Queue ID even when using this approach. When a handover is triggered by a guardrail or a supervisor takeover via Listen & intervene, there is no agent call to supply the parameter — the fallback Queue ID is used instead. For agent-initiated handovers, the runtime value from the agent takes precedence.

Alternatively, if you always route to the same queue, enter a static Queue ID directly in the action configuration. This is useful when you have separate handover actions per team or intent.

customer_support_tier2

Phone routing​

Enter the phone number to route the call to, including the country code:

+31612345678

Studio converts a Dutch number without a country code, such as 0182 223830, for you. When you set up the action through the API, send the number in international format without spaces, for example +31612345678.

Studio only saves real phone numbers. To demo a transfer without ringing anyone, tick Use the demo number under the field. This fills in +31600000000. Web calls and the Demo Playground show the transfer without dialling, and a phone call to the agent cannot be transferred to it.

To route dynamically, use Go template syntax in the Phone number field. You can reference conversation variables, static variables, and action parameters:

  • {{ .variables.call.from }} — the caller's phone number
  • {{ .variables.call.to }} — the number the caller dialled
  • {{ .parameters.phone }} — a parameter the agent collects at runtime via the Parameters Schema

For example, to route based on which number was dialled:

{{ if eq .variables.call.to "+31970XXXXXXX" }}+31970XXXXXXY{{ else }}+31612345678{{ end }}

From number​

The From number controls which caller ID the recipient sees on the transferred call:

  • Default (original caller) — passes through the original caller's phone number. This is the default. For SIP connections, this falls back to the inbound number because the outbound trunk is resolved by the from number.
  • Inbound number — uses the number the caller originally dialled (the DID).
  • A specific outbound number — uses one of your configured outbound trunk provider phone numbers. Only applies to SIP connections.

SIP routing​

Enter the SIP URI to transfer the call to:

sip:queue@pbx.example.com

To route dynamically, use Go template syntax in the SIP target field. Templates can reference .variables.*, .static_variables.*, and .parameters.* (values collected via the Parameters Schema). The SIP target must always start with a literal sip: or sips: prefix, so only the part after it can be templated. With the INVITE method (the default, described below), the host must also be a literal — only the user part and any URI parameters may be templated, so the call can only be transferred to the host you configured. To route to a dynamic host, use REFER. For example, to route based on which number was dialled:

sip:{{ if eq .variables.call.to "638472019" }}sales{{ else }}support{{ end }}@pbx.example.com

You can also route based on a substring match, using the contains, lower, and other string functions available to templates. For example, to route calls whose From header mentions "acme" to a dedicated queue:

sip:queue@pbx.example.com;campaign={{ if .variables.call.sip_headers.From | lower | contains "acme" }}1001{{ else }}9999{{ end }}
Inbound SIP headers are caller-controlled

SIP headers on an inbound call (such as From) are supplied by the caller or their carrier and are not trustworthy input. Use template conditionals on these headers only to choose among a fixed set of admin-defined destinations, as in the example above. Never use header values to construct the destination itself (for example, interpolating a header directly into the SIP URI), since that would let a caller influence where the call is transferred to.

Choose the transfer method:

  • INVITE: Keeps the call anchored through Stellar. This is the usual method and works with any trunk. It needs an auth connector for digest authentication if your PBX requires it. The host in the SIP target must be a literal (only the user part and URI parameters may be templated); a templated host is rejected when you save.
  • REFER: Hands the call off to the remote side, which then completes the transfer itself. On trunk-provider calls, this requires a trunk that allows REFER, a per-trunk setting a super admin controls that is off by default for new trunk providers. REFER allows a templated host, so use it when the transfer host itself must be chosen dynamically.

A REFER on a trunk-provider call whose trunk does not allow it fails the transfer, and there is no automatic fallback to INVITE, so select INVITE for those trunks. Tenant SIP credential calls do not use this per-trunk toggle; REFER remains subject to destination screening. See Call transfer for the trunk setting and details on how each method works.

Authentication connector​

Optionally select a SIP digest authentication connector to provide credentials for the outbound INVITE. This applies when INVITE is selected as the SIP method. The REFER method does not use these credentials, since the remote PBX handles the outbound leg independently.

Outbound X-headers​

Define custom SIP X-headers to include on the outgoing REFER or INVITE. Use these to pass conversation context — such as a case ID, caller intent, or summary — to your PBX or contact center.

Each header has a name and a value. The X- prefix is added automatically, so enter just the name (e.g., Case-Id, not X-Case-Id). Values support Go template syntax, so you can reference conversation variables, static variables, and action parameters:

Template variableSource
.variables.*Conversation variables (including call metadata)
.static_variables.*Static variables defined on the agent
.parameters.*Values the agent collects via the Parameters Schema

Example — passing a case ID and summary to a PBX:

Header nameValue
Case-Id{{ .parameters.case_id }}
Summary{{ .parameters.summary }}
Caller{{ .variables.call.from }}
info

Header names may only contain letters, numbers, hyphens, and underscores. You can define up to 16 headers. Values are truncated at 1,024 bytes.

When outbound X-headers are configured, they replace the implicit variable-to-header mapping described below. If no outbound headers are configured, the gateway falls back to sending extra Parameters Schema fields as X-headers for backwards compatibility.

Passing context to the contact center​

Any extra fields you define in the Parameters Schema are forwarded to the receiving system alongside the routing target. This lets you pass conversation context — such as a summary, reason, or priority — so the human agent receiving the call already has relevant background.

How context is forwarded:

  • Genesys (queue): Extra fields are sent as output variables in the disconnect message, available as context data on the incoming interaction.
  • SIP (with outbound X-headers): The explicitly configured outbound X-headers are sent on the REFER or INVITE. This is the recommended approach because it gives you full control over header names and supports template expressions.
  • SIP (without outbound X-headers): Extra Parameters Schema fields are sent as variables in the transfer event, and the SIP gateway maps them to X-headers automatically. This is the legacy behaviour and is used as a fallback when no outbound headers are configured.

Parameters Schema example (queue ID + summary):

{
"type": "object",
"properties": {
"queue_id": {
"type": "string",
"enum": ["sales", "support", "billing"]
},
"summary": {
"type": "string",
"description": "A brief summary of the conversation and the reason for the handover."
}
},
"required": ["queue_id", "summary"]
}

The agent will collect both values before initiating the transfer. The receiving agent in Genesys (or the SIP endpoint) gets the summary as part of the interaction context — no screen pop or manual note-taking needed.

You can add any number of extra fields this way, for example reason, priority, customer_id, or language.

Fallback announcement​

Used when a handover is triggered by a guardrail or a supervisor takeover via Listen & intervene. In these cases, the agent will first speak the specified message before initiating the transfer. For handovers triggered in the normal flow of a conversation (not by a guardrail or supervisor), the agent follows its regular instructions to decide what to say before transferring. Leave this blank if you want these handovers to happen immediately without a spoken message.

I'm transferring you to a human representative.

Example: dynamic queue routing with context​

Name: transfer_to_team
Description: Transfer the customer to the appropriate team. Use when the customer needs specialist help or requests a human agent.
- Use queue 'sales' for purchase or upgrade enquiries
- Use queue 'support' for technical or account issues
- Use queue 'billing' for payment or invoice questions
Before transferring, summarise the conversation in the 'summary' field.

Type: Queue
Queue ID: support
Parameters Schema:
{
"type": "object",
"properties": {
"queue_id": {
"type": "string",
"enum": ["sales", "support", "billing"]
},
"summary": {
"type": "string",
"description": "A brief summary of the conversation and the reason for the handover."
}
},
"required": ["queue_id", "summary"]
}
Fallback announcement: I'm transferring you to a human representative.

Fallback handover action​

In your agent's Advanced tab, you can designate one handover action as the Fallback Handover Action. This action triggers automatically when an unrecoverable error occurs during a conversation (e.g. voice provider connection lost, internal server error), preventing the caller from being silently disconnected.

If no fallback handover action is configured, fatal errors result in the call being disconnected.

Error context passed on fallback​

When a fallback handover is triggered by an error, the following variables are passed to the receiving system (e.g. available as output variables in a Genesys Architect flow):

VariableDescriptionExample
stellar.error.codeMachine-readable error codevoice_provider_connection_error
stellar.error.messageUser-facing error messageAn unexpected error occurred during conversation
stellar.error.severityError severity levelfatal
stellar.error.correlation_idUnique ID for log correlation by Stellar support550e8400-e29b-41d4-a716-446655440000

You can use these in your call routing logic to route error handovers to a specific queue, surface context to the human agent, or log the correlation ID for troubleshooting with Stellar support.

Email agents (Dixa inboxes)​

An email agent assigned to a single Dixa inbox can hand a conversation over to a human queue in Dixa. The action runs in the On receive phase: the Email phases field is fixed to On receive. Studio doesn't offer Handover for an agent that only serves Outlook, Exchange or Zendesk inboxes. For an agent with more than one inbox, Studio lists Handover greyed out with the reason, because the target could be a queue that another of its inboxes hands straight back to Stellar. In both cases, saving a handover action through the API is rejected.

The email form differs from the voice settings above:

  • The type is always Queue. There are no phone or SIP options, no fallback announcement, and no parameters schema to edit.
  • The queue is fixed in the action. The runtime queue_id parameter described in Queue routing does not apply to email, so create one action per target queue, such as hand_over_to_billing and hand_over_to_sales, and describe in each description when the agent should use it.
  • When the agent calls the action, it gives a short reason. The reason is not sent to Dixa.

Configure the action​

Open the email agent's Actions tab, add an action and choose Handover. Besides the name and description, the form has one field, Hand over to queue: the Dixa queue the conversation moves to. Queues are listed live from the agent's Dixa inbox. The queues that inbox already handles are greyed out, because handing a conversation over into one of them wouldn't take it away from Stellar; hover over one to see why. If the agent isn't assigned to a Dixa inbox yet, the field asks you to assign it to one first.

Name: hand_over_to_billing
Description: Hand the conversation over to the billing team. Use when the customer asks about an invoice, a payment or a refund that you cannot resolve yourself.
Hand over to queue: Billing

The same rule holds from the inbox side. Saving the inbox fails when you add a queue that one of its agent's handover actions targets, or when you assign it an agent that hands over to one of its queues. Change the handover action's queue first. If the inbox runs the agent's published version, publish the change; if it's pinned to a version, pin one without that target. Then edit the inbox.

What happens in Dixa​

When the agent calls the action, Stellar transfers the conversation to the queue. The conversation then leaves the queues the inbox handles, and Stellar stops processing it: later customer messages in that conversation are ignored. The same happens when a person in Dixa transfers a conversation out of the inbox's queues.

A handover doesn't end the run. The agent can post a reply or a draft note before it hands over, for example "I've passed your question to our billing team". Tell the agent in its instructions to reply first and then call the handover action.

If Dixa rejects the transfer, for example because the queue was deleted in Dixa, the agent receives a failed result and the conversation stays with Stellar.

In Studio​

A handed-over email is read-only. You can't send it from Studio, because that would post as the agent into a conversation a human queue now owns. The handover moves the whole conversation, so its earlier emails become read-only too, including one with a composed reply that nobody sent yet. When nothing was sent or drafted for the email, it shows Handed over to a queue where a draft or sent status would otherwise appear.

Next steps​

  • Configure guardrails that automatically trigger this handover action when certain conditions are met
  • Test the handover in the Playground
  • Use Listen & intervene to manually trigger a takeover during live calls