> ## 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.

#### `handoff`

Initiates a call handoff after the function executes. The `type` and `reason` fields match your configured [handoff destination](/call-handoff/introduction). The nested object specifies the SIP method.

<Tabs>
  <Tab title="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>

  <Tab title="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": "2222222",
          "outbound_caller_id": conv.caller_number,
          "outbound_endpoint": "<ADD_YOUR_OUTBOUND_ENDPOINT_NAME>",
          "sip_headers": {
            "X-ANY_HEADER_NAME": "header"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="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"
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

You can also trigger handoffs using [`conv.call_handoff()`](/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.
</Note>

#### `variant`

Switches the conversation to a different variant. The value must match an existing variant name configured in [variant management](/variant-management/introduction). 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:

<AccordionGroup>
  <Accordion title="utterance + handoff" icon="phone-arrow-up-right" defaultOpen>
    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>

  <Accordion title="utterance + hangup" icon="phone-slash">
    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>

  <Accordion title="utterance + content" icon="comments">
    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."
    }
    ```
  </Accordion>
</AccordionGroup>

## Related pages

<CardGroup cols={3}>
  <Card title="Start tool" icon="play" href="/tools/start-tool">
    Return values supported in the start function.
  </Card>

  <Card title="Delay control" icon="clock" href="/tools/delay-control">
    Add filler phrases while long-running functions execute.
  </Card>

  <Card title="Transition functions" icon="code" href="/flows/transition-functions">
    Return values in the context of flow step routing.
  </Card>
</CardGroup>
