> ## Documentation Index
> Fetch the complete documentation index at: https://docs.poly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Return values

> Control agent behavior with strings, utterances, handoffs, and other return types from functions.

**This page requires Python familiarity.** It covers the return interface for functions written in Python.

Return a string or dictionary from your function to control the agent's next action, including what to say, whether to transfer the call, or how to configure listening behavior.

### String return

You can return a simple string, which will be used as the system prompt for the virtual agent:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return "Tell the user that you cannot assist with their request"
```

### Dictionary return

You can return a dictionary to specify more detailed and deterministic instructions. The following fields can be used individually or in combination.

#### `content`

Equivalent to returning a string, this field specifies the system prompt:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "content": "Tell the user that you cannot assist with their request"
}
```

#### `utterance`

Specifies the exact phrase the virtual agent will deliver after executing the function (spoken for voice, displayed for webchat):

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "utterance": "I cannot assist with your request."
}
```

**Note**: If both `content` and `utterance` are returned:

* The agent will stream the `utterance` to the user and end the turn.
* The `content` rules will apply to the next turn.

#### `utterance_channel`

Controls how the `utterance` is delivered. Defaults to `"SPEECH"`, which speaks the utterance through TTS. Set to `"DTMF"` to transmit the utterance as DTMF keypad tones instead of speech – useful when the agent needs to send digits to an IVR or other automated system during [outbound calling](https://docs.poly.ai/voice-channel/numbers/outbound-calling.md).

The `utterance` string must contain the digits to send (`0`–`9`, `*`, `#`). The agent does not speak them.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "utterance": "1234#",
  "utterance_channel": "DTMF"
}
```

> [!NOTE]
>
> `utterance_channel` only takes effect when `utterance` is also set. The call must be running on a telephony channel that supports DTMF output – it is not available in webchat or with the realtime model.

#### `handoff`

Initiates a call handoff after the function executes. The `type` and `reason` fields match your configured [handoff destination](https://docs.poly.ai/voice-channel/handoffs.md). The nested object specifies the SIP method.

> [tab] SIP REFER (default)
>
> Transfers the call and drops PolyAI from it:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> return {
>   "handoff": {
>     "type": "CALL_CENTER",
>     "reason": "SPEAK_TO",
>     "refer": {
>       "phone_number": "12345"
>     }
>   }
> }
> ```

> [tab] SIP INVITE
>
> Creates a bridged call where PolyAI stays on the line between both parties:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> return {
>   "handoff": {
>     "type": "CALL_CENTER",
>     "reason": "SPEAK_TO",
>     "invite": {
>       "phone_number": "+442079460123",
>       "outbound_caller_id": conv.caller_number,
>       "outbound_endpoint": "<ADD_YOUR_OUTBOUND_ENDPOINT_NAME>",
>       "record_handoff": False,
>       "sip_headers": {
>         "X-ANY_HEADER_NAME": "header"
>       }
>     }
>   }
> }
> ```
>
> Set `record_handoff` to `True` to record the call after the handoff. The recording includes the conversation between the caller and the handoff destination. The default value is `False`.
>
> > [!NOTE]
> >
> > `record_handoff` is only available with SIP INVITE. With SIP REFER, PolyAI leaves the call, so PolyAI cannot record the transferred call.

> [tab] SIP BYE
>
> Signals that the PolyAI call leg is over, returning control to the client's SBC:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> return {
>   "handoff": {
>     "type": "CALL_CENTER",
>     "reason": "CONTAINED",
>     "bye": {
>       "sip_headers": {
>         "X-Outcome": "contained"
>       }
>     }
>   }
> }
> ```

You can also trigger handoffs using [`conv.call_handoff()`](https://docs.poly.ai/tools/classes/conv-object), which supports dynamic `destination`, `reason`, and `utterance` parameters. Use the dictionary return for fine-grained SIP control; use `conv.call_handoff()` for simpler routing.

#### `hangup`

Ends the conversation after the function executes. For voice, this disconnects the call; for webchat, this closes the session:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "hangup": True
}
```

#### `listen`

Configures the agent to listen on the next turn. Must be combined with an `utterance` for ASR timeout settings to take effect.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "utterance": "Can I help you with anything else?",
  "listen": {
    "asr": {
      "timeout": 20
    }
  }
}
```

The `listen` object supports these configuration keys:

| Key | Type | Description |
| - | - | - |
| `listen` | bool | Whether to listen for input (default `True`) |
| `delayed_response` | bool | Enable delayed response mode – the client sends an empty input to retrieve the response |
| `asr` | dict | ASR configuration: `timeout`, `keywords`, `custom_biases`, `fields`, `corrections` |
| `dtmf` | dict | DTMF configuration: `num_digits`, `first_digit_timeout`, `inter_digit_timeout`, `finish_on_key`, `early_listening`, `is_pii` |
| `channel` | str | Input channel: `"SPEECH"` (default), `"DTMF"`, or `"SPEECH_AND_DTMF"` |
| `barge_in` | dict | Barge-in configuration: `is_enabled`, `interruption_window` |
| `smart_vad` | dict | Smart VAD configuration: `is_enabled`, `max_extensions`, `max_extension_duration` |
| `interjection` | dict | Interjection configuration: `enable`, `frequency` (seconds) |

**Example with DTMF:**

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "utterance": "Please enter your 6-digit code followed by the hash key.",
  "listen": {
    "channel": "SPEECH_AND_DTMF",
    "dtmf": {
      "num_digits": 6,
      "finish_on_key": "#",
      "first_digit_timeout": 5,
      "inter_digit_timeout": 2,
      "is_pii": True
    }
  }
}
```

> [!NOTE]
>
> ASR timeout doesn't apply to DTMF-only input. If using both channels, make sure you include an `utterance` so the ASR settings take effect.

#### `variant`

Switches the conversation to a different variant. The value must match an existing variant name configured in [Variants](https://docs.poly.ai/knowledge/variants/introduction.md). Use this to route callers to location-specific or segment-specific conversation flows mid-call.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "variant": "orleans"
}
```

You can combine `variant` with `utterance` to confirm the switch to the user:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
return {
  "utterance": "Let me connect you with the Orleans location.",
  "variant": "orleans"
}
```

## Combining return fields

You can return multiple fields together. Common combinations:

> [accordion] utterance + handoff
>
> Say something before transferring – the most common handoff pattern:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> return {
>   "utterance": "Let me transfer you to a specialist who can help with that.",
>   "handoff": {
>     "type": "CALL_CENTER",
>     "reason": "SPEAK_TO",
>     "refer": { "phone_number": "12345" }
>   }
> }
> ```

> [accordion] utterance + hangup
>
> Say a closing message before ending the call:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> return {
>   "utterance": "Thanks for calling, have a great day!",
>   "hangup": True
> }
> ```

> [accordion] utterance + content
>
> Deliver a specific phrase now and set instructions for the next turn:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> return {
>   "utterance": "I've updated your reservation.",
>   "content": "The reservation has been changed. Ask if there's anything else you can help with."
> }
> ```

## Related pages

> [card] [Start tool](https://docs.poly.ai/tools/start-tool.md)
>
> Return values supported in the start function.

> [card] [Delay control](https://docs.poly.ai/tools/delay-control.md)
>
> Add filler phrases while long-running functions execute.

> [card] [Transition functions](https://docs.poly.ai/flows/transition-functions.md)
>
> Return values in the context of flow step routing.
