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

# Routing | Service Location - v0.2

> The composite tool that asks the caller which state and suburb they need service in, confirms the locality, and finds the routing endpoint that covers it, ready for a Handoff step to dial.

## What it does

**Routing | Service Location - v0.2** works out *where* the caller needs service and, from that, *which of your routing endpoints* should take the call. In one step it:

1. asks which state and suburb the caller needs service in,
2. matches their answer to a known locality and reads it back for the caller to confirm,
3. if nothing matches, asks for a larger nearby town or suburb, a postcode, or both,
4. looks up the routing endpoint that covers the confirmed area, following your team's location routing rules, and
5. if several endpoints cover the area, offers them to the caller by name and lets them choose.

It is a [composite tool](/tools/composite-tools): the whole exchange runs behind a single step. **It never dials.** It hands the matched endpoint to your script in `{{route.endpoint_id}}`, and a [Handoff](/tools/warm-handoff) step after it makes the transfer. Keeping the transfer in your own flow lets each script choose warm or cold transfer, its own handover wording and its own fallback.

Which endpoints cover which areas is set up under **Numbers & Routing**: the endpoints' **Coverage** and the team's **Routing settings**. See [Location Routing](/routing/location-routing).

***

## Use cases

* **Route to the local branch or franchise.** A national number sends each caller to the service centre that covers their suburb.
* **Offer a choice of nearby centres.** Where more than one location covers an area, the caller picks the one they want.
* **Capture the service location only.** With **Lookup Mode** set to locality only, the tool confirms the suburb, state and postcode and stops there, for scripts that need the location but route some other way.

***

## Inputs

| Setting                   | Description                                                                                                                                                                                                                                                                | Default                                                                                              |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Opening Ask**           | The first question, spoken word for word. It must end in a question mark so the assistant waits for the answer. Ask for the *service* location, not the caller's home address.                                                                                             | "Thanks `{{contact.first_name}}`. What state and suburb do you need service in?"                     |
| **Fallback Endpoint**     | The routing endpoint to use when no covering endpoint can take the call. It must belong to your team. The tool only records it for your script; it never dials it. Required.                                                                                               | —                                                                                                    |
| **Fallback Name**         | How the fallback destination is named to the caller, for example `our national support team`. Written to `{{route.destination_name}}` when the tool finishes false, so your handover line can name it. Required.                                                           | —                                                                                                    |
| **Max Postcode Attempts** | How many times the postcode may be asked before giving up (1 to 5). Only an answer that can't be used (too few digits, an unknown postcode, a failed lookup) counts as an attempt. A valid postcode with no coverage finishes straight away rather than being asked again. | `2`                                                                                                  |
| **Context**               | Optional background the assistant can use to explain why it needs the location, for example "The service location decides which local centre takes the call."                                                                                                              | —                                                                                                    |
| **Lookup Mode**           | **Locality + service centre endpoint**: confirm the locality, then find the endpoint. **Locality only (no endpoint lookup)**: stop once the locality is confirmed. `{{route.endpoint_id}}` stays empty and the fallback isn't used.                                        | Locality + service centre endpoint                                                                   |
| **No Match Recovery**     | What to do when the answer can't be matched, or the caller rejects the read-back without naming another place. **Ask for a postcode**, **Ask for a nearby town or suburb**, or **Nearby suburb first, then postcode**.                                                     | Ask for a postcode                                                                                   |
| **Nearby Suburb Ask**     | The question used by the nearby-suburb recovery, spoken word for word. Must end in a question mark.                                                                                                                                                                        | "Sorry, I couldn't find that one. Is there a larger town or suburb nearby that I could use instead?" |
| **Max Suburb Attempts**   | How many nearby-suburb asks are allowed (1 to 3) before moving on to the postcode ask or finishing false. Used only by the nearby-suburb recovery options.                                                                                                                 | `1`                                                                                                  |

***

## How it runs

* **Postcode up front.** If the caller gives a postcode in their first answer, the tool uses it straight away.
* **Read-back.** The matched locality is always read back for a yes or no. If the caller says no and names another place, that place is tried once more.
* **Ambiguous names.** If a suburb name exists in more than one place, or the caller didn't say a state, the tool asks which one they mean.
* **Choosing a centre.** If more than one endpoint covers the area, the tool names them and asks which the caller would like.
* **Closed endpoints.** An endpoint whose [schedule](/routing/schedules) is closed but that forwards elsewhere still counts. The Handoff step follows the same forwarding chain. When every covering endpoint is closed with nowhere to forward, the tool finishes false with the status `unavailable`.
* **Lookups that time out** are retried once, silently, before the tool gives up with the status `error`.

***

## Outputs

| Output                | Description                                                                                                                                                            |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **result**            | Hidden boolean that routes the step. True when the locality was confirmed and, in endpoint mode, one endpoint was found (or chosen by the caller).                     |
| **Endpoint ID**       | The routing endpoint to dial. Put `{{route.endpoint_id}}` in the Handoff step's **Routing Endpoint**. Empty on a false result, and always empty in locality-only mode. |
| **Destination Name**  | The name of the matched centre, to announce before transferring. On a false result, your **Fallback Name**.                                                            |
| **Status**            | `matched`, `fallback`, `unavailable` or `error`. Branch your follow-up wording on it.                                                                                  |
| **Resolution ID**     | The identifier of the routing decision, for matching the call to its routing record.                                                                                   |
| **Locality Name**     | The confirmed suburb or town.                                                                                                                                          |
| **Locality State**    | The confirmed state code.                                                                                                                                              |
| **Locality Postcode** | The confirmed postcode or postcodes.                                                                                                                                   |

## Variables this tool writes

| Variable                      | Type   | Example                                | Description                                                                                                                                    |
| ----------------------------- | ------ | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `{{route.endpoint_id}}`       | string | `3f6c2c1a-8b0d-4e2f-9a41-6c7d5e8f9a01` | The routing endpoint to dial. Empty on a false result and in locality-only mode.                                                               |
| `{{route.destination_name}}`  | string | `Castle Hill`                          | The matched service centre's name, or the Fallback Name on a false result.                                                                     |
| `{{route.status}}`            | string | `matched`                              | `matched`, `fallback` (no coverage, or recovery ran out), `unavailable` (the covering centres are closed) or `error` (the lookup failed).      |
| `{{route.reason}}`            | string | `no_coverage`                          | More detail on a status other than `matched`, for example `no_coverage`, `recovery_exhausted`, `unknown_postcode` or `chosen_endpoint_closed`. |
| `{{route.resolution_id}}`     | string | `9a1e4f20-5c3b-4d8e-b6a7-2f0c1d9e8b34` | The identifier of the routing decision.                                                                                                        |
| `{{route.locality_name}}`     | string | `Castle Hill`                          | The confirmed suburb or town. Empty when the location came from a postcode alone.                                                              |
| `{{route.locality_state}}`    | string | `NSW`                                  | The state code. From a postcode alone, set only when the postcode lies in one state.                                                           |
| `{{route.locality_postcode}}` | string | `2154`                                 | The postcode, comma-separated when a suburb spans several (for example `2125, 2126`), or the postcode the caller said.                         |

The `route` namespace also holds the tool's own working fields (the inputs, the caller's words, the candidates it proposed). They are private to the tool, and the next use of the tool in the call overwrites the whole namespace. If a later step needs a value after that, map the output onto a custom variable.

***

## Routing and wiring

Wire the tool to two Handoff steps: one for the matched endpoint and one for your fallback.

```text theme={null}
Step 10 (Tool)  Routing | Service Location - v0.2
   true      → Step 20
   otherwise → Step 30

Step 20 (Voice, Verbatim)  "I'll connect you to {{route.destination_name}} now."
   otherwise → Step 21

Step 21 (Tool)  Handoff
   Routing Endpoint:          {{route.endpoint_id}}
   Warm Handoff - Agent Name: {{route.destination_name}}
   Transfer Mode:             cold
   Ring Timeout:              30
   otherwise → Step 30

Step 30 (Tool)  Handoff
   Routing Endpoint:          Head office support (your Fallback Endpoint)
   Warm Handoff - Agent Name: {{route.destination_name}}
```

* **true**: the locality is confirmed. In endpoint mode, dial `{{route.endpoint_id}}`. In locality-only mode, read the `{{route.locality_*}}` values and carry on.
* **Otherwise**: branch on `{{route.status}}`. `fallback` and `unavailable` both go to the fallback Handoff. `error` means the lookup itself failed; treat it the same way.
* The endpoint's own schedule, fallback and forwarding rules apply when the Handoff step dials it. You don't need a separate opening-hours check unless the script should say something specific out of hours.
* `{{route.endpoint_id}}` holds a routing endpoint, never a phone number. It only works in a field that takes a routing endpoint, such as the Handoff tool's **Routing Endpoint**.
* The postcode is collected by voice only.

***

## Next Steps

* [Handoff](/tools/warm-handoff) — the tool that makes the transfer
* [Location Routing](/routing/location-routing) — coverage, routing settings and lookup previews
* [Composite Tools](/tools/composite-tools) — how composite steps run and write their outputs
* [Variables](/flows/variables#route) — the `route` namespace
