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

# reach_person()

> Confirm you have the right person on the line for outbound calls

<Tabs>
  <Tab title="Python">
    For outbound calls, `reach_person()` handles the critical first step: confirming you have the right person on the line before proceeding. It automatically handles answering machines, gatekeepers, wrong numbers, and refusals.

    ```python signature theme={null}
    def reach_person(
        contact_full_name: str,
        *,
        greeting: str | None = None,
        voicemail_message: str | None = None,
        voicemail_hangup: bool = False,
        outcomes: list[ReachPersonOutcome] | None = None,
    )
    ```

    | Parameter | Type | Default | Description |
    | - | - | - | - |
    | `contact_full_name` | `str` | — | The full name of the person you're trying to reach. |
    | `greeting` | `str \| None` | `None` | Custom greeting message. Overrides the default introduction. |
    | `voicemail_message` | `str \| None` | `None` | Message to leave if voicemail is reached. Mutually exclusive with `voicemail_hangup` and with `set_voicemail_action()`. |
    | `voicemail_hangup` | `bool` | `False` | Immediately hang up if voicemail is reached. Mutually exclusive with `voicemail_message` and with `set_voicemail_action()`. |
    | `outcomes` | `list[ReachPersonOutcome] \| None` | `None` | Custom outcome routing. Defaults to five outcomes: available, unavailable, voicemail, wrong\_number, and do\_not\_contact. Use this to define additional or different outcomes. |

    ```python example.py theme={null}
    @agent.on_call_start
    def on_call_start(call: guava.Call):
        call.reach_person(
            contact_full_name=call.get_variable("contact_name"),
            voicemail_message="Please give us a call back at your convenience."
        )

    @agent.on_reach_person
    def on_reach_person(call: guava.Call, outcome: str):
        if outcome == "available":
            call.set_task(
                "main_task",
                checklist=[...],
            )
        else:
            call.hangup("Appropriately end the call.")
    ```
  </Tab>

  <Tab title="TypeScript">
    For outbound calls, `reachPerson()` handles the critical first step: confirming you have the right person on the line before proceeding. It automatically handles answering machines, gatekeepers, wrong numbers, and refusals.

    ```typescript signature theme={null}
    reachPerson(
      contactFullName: string,
      options?: {
        greeting?: string;
        voicemailMessage?: string;
        voicemailHangup?: boolean;
        outcomes?: ReachPersonOutcome[];
      },
    ): Promise<void>
    ```

    | Parameter | Type | Default | Description |
    | - | - | - | - |
    | `contactFullName` | `string` | — | The full name of the person you're trying to reach. |
    | `options.greeting` | `string` | — | Custom greeting message. Overrides the default introduction. |
    | `options.voicemailMessage` | `string` | — | Message to leave if voicemail is reached. Mutually exclusive with `voicemailHangup` and with `setVoicemailAction()`. |
    | `options.voicemailHangup` | `boolean` | `false` | Immediately hang up if voicemail is reached. Mutually exclusive with `voicemailMessage` and with `setVoicemailAction()`. |
    | `options.outcomes` | `ReachPersonOutcome[]` | — | Custom outcome routing. Defaults to five outcomes: available, unavailable, voicemail, wrong\_number, and do\_not\_contact. Use this to define additional or different outcomes. |

    ```typescript example.ts theme={null}
    agent.onCallStart(async (call: guava.Call) => {
      await call.reachPerson(await call.getVariable("contactName") as string, {
        voicemailMessage: "Please give us a call back at your convenience.",
      });
    });

    agent.onReachPerson(async (call: guava.Call, outcome: string) => {
      if (outcome === "available") {
        await call.setTask({ taskId: "main_task", checklist: [...] });
      } else {
        await call.hangup("Appropriately end the call.");
      }
    })
    ```
  </Tab>
</Tabs>

## What happens on the call

<Tabs>
  <Tab title="Python">
    When `reach_person()` is invoked, the agent automatically:

    1. **Greets** whoever answers and introduces itself (organization + purpose).
    2. **Asks for the contact** by name. If someone else answered, asks to speak with or be transferred to the contact.
    3. **Determines availability** and records the contact's availability in a `contact_availability` field.
    4. **Fires `agent.on_reach_person`** with the outcome key. The five default outcomes are:

       * `"available"` — the intended contact is on the line.
       * `"unavailable"` — someone else or an IVR answered and the contact could not be reached.
       * `"voicemail"` — an answering machine or voicemail system was reached.
       * `"wrong_number"` — the number does not belong to the contact.
       * `"do_not_contact"` — the contact asked not to be called again.

       If you provided custom `outcomes`, those are used instead.
  </Tab>

  <Tab title="TypeScript">
    When `reachPerson()` is invoked, the agent automatically:

    1. **Greets** whoever answers and introduces itself (organization + purpose).
    2. **Asks for the contact** by name. If someone else answered, asks to speak with or be transferred to the contact.
    3. **Determines availability** and records the contact's availability in a `contact_availability` field.
    4. **Fires `agent.onReachPerson`** with the outcome key. The five default outcomes are:

       * `"available"` — the intended contact is on the line.
       * `"unavailable"` — someone else or an IVR answered and the contact could not be reached.
       * `"voicemail"` — an answering machine or voicemail system was reached.
       * `"wrong_number"` — the number does not belong to the contact.
       * `"do_not_contact"` — the contact asked not to be called again.

       If you provided custom `outcomes`, those are used instead.
  </Tab>
</Tabs>

## Voicemail handling

<Tabs>
  <Tab title="Python">
    <Warning>
      `reach_person()` and [`set_voicemail_action()`](/sdk-reference/set-voicemail-action) both handle voicemail and **cannot be used together**. If you set `voicemail_message` or `voicemail_hangup` on `reach_person()`, do not call `set_voicemail_action()` — and vice versa. Using both raises an error.
    </Warning>
  </Tab>

  <Tab title="TypeScript">
    <Warning>
      `reachPerson()` and [`setVoicemailAction()`](/sdk-reference/set-voicemail-action) both handle voicemail and **cannot be used together**. If you set `voicemailMessage` or `voicemailHangup` on `reachPerson()`, do not call `setVoicemailAction()` — and vice versa. Using both throws an error.
    </Warning>
  </Tab>
</Tabs>

## Common mistake: redundant introductions

<Tabs>
  <Tab title="Python">
    <Warning>
      By the time `on_reach_person` fires, the agent has already introduced itself and stated the purpose of the call. Do **not** re-introduce in the first task after `reach_person`.
    </Warning>

    ```python theme={null}
    # WRONG — redundant introduction
    @agent.on_reach_person
    def on_reach_person(call: guava.Call, outcome: str):
        if outcome == "available":
            call.set_task("survey", checklist=[
                guava.Say("Hi, this is Grace from Acme Corp, I'm calling about..."),  # Already said this
                ...
            ])

    # RIGHT — go straight to content
    @agent.on_reach_person
    def on_reach_person(call: guava.Call, outcome: str):
        if outcome == "available":
            call.set_task("survey", checklist=[
                guava.Say("I just have a few quick questions for you today."),
                ...
            ])
    ```
  </Tab>

  <Tab title="TypeScript">
    <Warning>
      By the time `onReachPerson` fires, the agent has already introduced itself and stated the purpose of the call. Do **not** re-introduce in the first task after `reachPerson`.
    </Warning>

    ```typescript theme={null}
    // WRONG — redundant introduction
    agent.onReachPerson(async (call: guava.Call, outcome: string) => {
      if (outcome === "available") {
        await call.setTask({ taskId: "survey", checklist: [
          guava.Say("Hi, this is Grace from Acme Corp, I'm calling about..."),  // Already said this
          ...
        ]});
      }
    });

    // RIGHT — go straight to content
    agent.onReachPerson(async (call: guava.Call, outcome: string) => {
      if (outcome === "available") {
        await call.setTask({ taskId: "survey", checklist: [
          guava.Say("I just have a few quick questions for you today."),
          ...
        ]});
      }
    });
    ```
  </Tab>
</Tabs>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.