> ## Documentation Index
> Fetch the complete documentation index at: https://developer.watson-orchestrate.ibm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Transfer End node

Use a Transfer End node to hand off the current conversation to a live agent. The node specifies which channels support the transfer and what messages to show the customer while the handoff is in progress.

A flow that contains a Transfer End node must be marked as a customer care escalation workflow. The escalation workflow is then referenced by a native agent that defines the conditions under which the transfer is triggered. For more information, see [Agent escalation to a live agent](../agents/escalation).

## Marking a flow as a customer care escalation workflow

Pass `is_customercare_escalation=True` in the `@flow` decorator:

```python Python theme={null}
from ibm_watsonx_orchestrate.agent_builder.flows import Flow, flow
from ibm_watsonx_orchestrate.agent_builder.flows.types import CustomerCareEscalationInput

@flow(
    name="customer_care_escalation_flow",
    display_name="Customer Care Escalation Flow",
    description="Escalation workflow that transfers users to a live agent.",
    input_schema=CustomerCareEscalationInput,
    is_customercare_escalation=True,
)
def build_customer_care_escalation_flow(aflow: Flow = None) -> Flow:
    ...
```

Alternatively, call the fluent method on the flow object inside the builder function:

```python Python theme={null}
aflow.is_customercare_escalation()
```

> [!NOTE]
>
> Escalation workflows are hidden from the default tools list. To include them, run `orchestrate tools list --include-escalation`.

## Input schema

Customer care escalation flows use `CustomerCareEscalationInput` as their input schema. The agent runtime populates both fields automatically before invoking the flow.

**channel\_type** `string` *required*

The current channel identifier, for example `genesys_bot_connector` or `sip`.

**condition\_id** `string` *required*

The escalation condition that triggered the transfer, for example `human_request` or `frustration`.

## Configuring a Transfer End node

A Transfer End node lists every channel that can receive a live-agent handoff. For each channel, you configure the messages shown to the customer and any metadata the channel requires.

```python Python theme={null}
from ibm_watsonx_orchestrate.agent_builder.flows.nodes import TransferEndNode
from ibm_watsonx_orchestrate.agent_builder.flows.types import TransferChannelType

transfer_end_node = aflow.transfer_end(name="transfer_to_agent")
```

### Configuring a channel — `configure_channel()`

Call `configure_channel()` once per supported channel to register the channel and set its availability messages.

**name** `TransferChannelType | string` *required*

The channel to configure. Accepts a `TransferChannelType` enum value (for example, `TransferChannelType.GENESYS_BOT_CONNECTOR`) or its string equivalent (`"genesys_bot_connector"`).

**agent\_available** `string` *required*

Message shown to the customer when a live agent is available.

**agent\_unavailable** `string` *required*

Message shown to the customer when no live agent is available.

Supported channel types are defined by `TransferChannelType`:

| Enum value | String value |
| - | - |
| `TransferChannelType.GENESYS_BOT_CONNECTOR` | `"genesys_bot_connector"` |
| `TransferChannelType.GENESYS_AUDIO_CONNECTOR` | `"genesys_audio_connector"` |
| `TransferChannelType.SIP` | `"sip"` |

> [!NOTE]
>
> By default, only `genesys_bot_connector` is enabled in the Transfer End node configuration. `sip` and `genesys_audio_connector` are provided as opt-in samples. Uncomment the relevant section in your flow definition to enable them.

**Example — Genesys Bot Connector (no extra properties required):**

```python Python theme={null}
transfer_end_node.configure_channel(
    name=TransferChannelType.GENESYS_BOT_CONNECTOR,
    agent_available="An agent will be with you shortly.",
    agent_unavailable="No agents are available right now. Please try again later.",
)
```

### Setting built-in channel properties — `map_output_variable()`

Some channels have platform-defined properties that must be populated. SIP requires a `service_desk_info` object that carries the transfer URI and method. You do not declare this property — configuring the SIP channel adds its schema automatically. Populate its fields with `map_output_variable()`.

**channel** `TransferChannelType | string` *required*

The target channel. Accepts a `TransferChannelType` value or its string equivalent.

**property\_path** `string` *required*

Dot-separated path to the property field, for example `"service_desk_info.uri"`.

**expression** `string` *required*

The value to assign. How this string is interpreted depends on `assignment_type`.

**assignment\_type** `string`

Controls how `expression` is read. Defaults to `"pyExpression"`.

| Value | `expression` is | Example |
| - | - | - |
| `"literal"` | A fixed value passed as-is | `'"refer"'` |
| `"variable"` | A flow variable path | `"flow.private.sip_uri"` |
| `"pyExpression"` (default) | A Python expression evaluated at runtime | `"'tel:+18005550001' if flow.input.condition_id == 'frustration' else 'tel:+18005550000'"` |

`map_output_variable()` returns the node, so calls can be chained.

**Example — SIP channel:**

```python Python theme={null}
transfer_end_node.configure_channel(
    name=TransferChannelType.SIP,
    agent_available="Connecting you to an agent.",
    agent_unavailable="No agents are available right now.",
)
transfer_end_node.map_output_variable(
    channel=TransferChannelType.SIP,
    property_path="service_desk_info.uri",
    expression='"tel:+18005551234"',
    assignment_type="literal",
).map_output_variable(
    channel=TransferChannelType.SIP,
    property_path="service_desk_info.transfer_method",
    expression='"refer"',
    assignment_type="literal",
)
```

### Adding custom channel properties — `add_custom_property()`

For channel-specific routing data that you define yourself, chain `add_custom_property()` calls after `configure_channel()`. This method declares the property in the channel's schema and populates it in one step.

**name** `string` *required*

The property name.

**value** `string`

A fixed value for the property. Use `value` for static data.

**expression** `string`

A flow expression evaluated at runtime. Use `expression` for dynamic data.

Provide either `value` or `expression`, not both.

> [!NOTE]
>
> The `summary` and `condition_id` fields are added to `transfer_metadata` automatically by the runtime. You do not need to declare or map them.

**Example — Genesys Bot Connector with custom routing properties:**

```python Python theme={null}
transfer_end_node.configure_channel(
    name=TransferChannelType.GENESYS_BOT_CONNECTOR,
    agent_available="An agent will be with you shortly.",
    agent_unavailable="No agents are available right now.",
).add_custom_property(
    "customer_tier",
    value='"Gold++"',
).add_custom_property(
    "priority",
    expression="'high' if flow.input.condition_id == 'frustration' else 'normal'",
)
```

## Full example

The following example builds a complete customer care escalation flow. It checks the incoming channel, routes to a condition-specific message, and hands off to a live agent via the Transfer End node.

```python Python theme={null}
from ibm_watsonx_orchestrate.agent_builder.flows import Flow, flow
from ibm_watsonx_orchestrate.agent_builder.flows.types import (
    CustomerCareEscalationInput,
    TransferChannelType,
)

@flow(
    name="customer_care_escalation_flow",
    display_name="Customer Care Escalation Flow",
    description="Transfers users to a live agent when an escalation condition is met.",
    input_schema=CustomerCareEscalationInput,
    is_customercare_escalation=True,
)
def build_customer_care_escalation_flow(aflow: Flow = None) -> Flow:
    check_channel = aflow.branch(
        name="check_channel",
        evaluator="flow.input.channel_type",
    )

    handle_condition = aflow.branch(
        name="handle_escalation_condition",
        evaluator="flow.input.condition_id",
    )

    transfer_end_node = aflow.transfer_end(name="transfer_to_agent")
    transfer_end_node.configure_channel(
        name=TransferChannelType.GENESYS_BOT_CONNECTOR,
        agent_available="An agent will be with you shortly.",
        agent_unavailable="No agents are available right now.",
    )

    # Wire nodes — omitted for brevity; see examples/flow_builder/customer_care_escalation
    return aflow
```

The compiled example is available at `examples/flow_builder/customer_care_escalation`. Run the following command from the `wxo-clients/` directory to compile it to JSON:

```bash theme={null}
python -m examples.flow_builder.customer_care_escalation.main
```

The output is written to `generated/customer_care_escalation_flow.json` and can be imported via the watsonx Orchestrate UI or CLI.

## Flow Builder UI equivalent

This pattern corresponds to the **Customer Care Escalation** template in the Flow Builder UI. To access it, select **New flow → Templates → Customer Care Escalation**. The node layout, branch conditions, and channel configuration match what the ADK produces.

## Related resources

* [Agent escalation to a live agent](../agents/escalation)
* [Building agentic workflows](https://developer.watson-orchestrate.ibm.com/tools/flows/building_flow.md)
* [`CustomerCareEscalationInput`](./building_flow) — standardised input schema
* [`@flow` decorator parameters](./building_flow#define-a-python-function-with-the-flow-decorator)
