> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.vapi.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.vapi.ai/_mcp/server.

# Pass context and variables

> Choose the conversation history a destination receives and pass variables through handoff arguments, tool results, or extraction.

A handoff carries **conversation messages** and **variable values** separately. Set `contextEngineeringPlan` on the destination to choose which earlier messages its model sees. The destination gets its own system prompt in every mode.

Values already collected in the call remain available to later assistants even if the destination receives no earlier messages.

> **Note**
>
> The destination's system prompt is the first `system` message in its `model.messages`. On a handoff, any additional `system` messages in that array are dropped, so combine all destination instructions into a single system message.

## Context engineering

Set `contextEngineeringPlan` on an assistant or squad destination. It filters the messages sent to that destination; it does not clear saved variables.

| Type                        | Earlier messages the destination receives                                                                                                       |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `all` (default)             | All earlier conversation messages, including tool calls and results. The previous system prompt is replaced by the destination's system prompt. |
| `lastNMessages`             | The most recent `maxMessages` messages. Use a positive value: `0` currently selects all messages.                                               |
| `userAndAssistantMessages`  | User and assistant messages; tool calls and tool results are excluded.                                                                          |
| `previousAssistantMessages` | Messages from before the current assistant received its incoming handoff. On the first handoff, there is no earlier assistant context to carry. |
| `none`                      | No earlier conversation messages.                                                                                                               |

For example, this destination receives the ten most recent messages:

```json
{
  "type": "assistant",
  "assistantName": "Specialist",
  "contextEngineeringPlan": {
    "type": "lastNMessages",
    "maxMessages": 10
  }
}
```

> **Warning**
>
> `previousAssistantMessages` and `none` filter the destination model's message history. They do not erase values already in the variable bag or remove messages from a full-history call artifact. If you handle sensitive information, control what is collected, stored, extracted, and passed in variables as well as message history.

## Variable extraction

Choose how a value reaches the destination based on its source:

| Value source                  | When it runs                                                                                                           | What reaches the destination                                                                     |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Standard call and time values | Vapi makes supported values available for the call or channel. See [Dynamic variables](/assistants/dynamic-variables). | Available values such as `customer.number`, `call.id`, and `now` can render in the prompt.       |
| Initial custom values         | Supply `assistantOverrides.variableValues` when starting the call.                                                     | Those named values can render in the destination prompt.                                         |
| Earlier tool response         | Configure `variableExtractionPlan.aliases` on the **result-producing tool**; it selects fields when the tool returns.  | Only selected alias values are saved. A JSON response alone is not copied into the variable bag. |
| Handoff arguments             | Define custom `function.parameters` on the handoff tool; the model fills them in the outgoing handoff tool call.       | Every argument except `destination` is added to the bag.                                         |
| Conversation content          | Define `variableExtractionPlan.schema` on the destination; a separate model request runs at handoff.                   | Top-level properties in the extracted object are added to the bag if extraction succeeds.        |
| Existing bag value            | Liquid runs when the destination prompt is rendered.                                                                   | A reference such as `{{customerName}}` reads the current value; it does not extract one.         |

At handoff, Vapi adds tool arguments, then any schema-extracted values, then the chosen destination's `assistantOverrides.variableValues` or `squadOverrides.variableValues`. If the same key is set more than once, the later value wins.

### Handoff arguments

Use `function.parameters` when the outgoing assistant can provide a value as it decides to hand off. This tool passes `customerIntent` to `Specialist`:

```json
{
  "type": "handoff",
  "destinations": [
    {
      "type": "assistant",
      "assistantName": "Specialist",
      "description": "Handle billing questions"
    }
  ],
  "function": {
    "name": "handoff_to_specialist",
    "parameters": {
      "type": "object",
      "properties": {
        "destination": {
          "type": "string",
          "enum": ["Specialist"]
        },
        "customerIntent": {
          "type": "string",
          "description": "The caller's reason for contacting billing"
        }
      },
      "required": ["destination", "customerIntent"]
    }
  }
}
```

The destination can use `{{customerIntent}}` in its prompt. `destination` selects the target and is not saved as a variable. For fixed destinations, Vapi derives the allowed destination values from the configured destinations. Dynamic routing can leave `destination` optional so the webhook can resolve it. Since the model supplies custom arguments, verify critical IDs against a trusted source.

### Destination schema extraction

Use `variableExtractionPlan.schema` on the destination when you need a separate request to extract information from the outgoing assistant's currently available conversation:

```json
{
  "type": "assistant",
  "assistantName": "Specialist",
  "variableExtractionPlan": {
    "schema": {
      "type": "object",
      "properties": {
        "customerName": {
          "type": "string",
          "description": "Name the caller gave during the conversation"
        }
      },
      "required": ["customerName"]
    }
  }
}
```

The destination can read the top-level property as `{{customerName}}`. A nested object can be read with a path such as `{{shippingAddress.city}}`. An earlier history filter can limit what the extraction request sees; it does not recover messages removed from the outgoing assistant's context.

Extraction is best effort. Without a `schema`, the plan adds nothing. If the request fails or returns a non-object, the handoff continues without new extracted values. A required schema property is not guaranteed to be available in the destination prompt.

Use [tool-result aliases](/tools/static-variables-and-aliases/extract-and-chain) on the tool that produces a response when you need exact fields from that response. A handoff destination's `variableExtractionPlan` uses its **`schema`** for conversation extraction; aliases there are not applied by the current handoff path.

### Reuse values after another handoff

Suppose assistant A passes `customerIntent` as a handoff argument to B. B extracts `customerName`, then hands off to C with `contextEngineeringPlan.type` set to `none`. C receives no earlier conversation messages, but can still use `{{customerIntent}}` and `{{customerName}}` from the shared variable bag. If B sets `customerIntent` again, its later value replaces A's value.

## Configuration paths and verification

The history and variable rules above apply to a completed assistant or squad handoff. Check how the handoff is configured:

| Path                                | What to check                                                                                                                                                                                                                           |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Saved squad, API or Dashboard       | Use a handoff tool on the outgoing assistant, or configure a squad member's Handoff Tools. For custom `function.parameters`, configure the tool itself; the squad member Handoff Tools setting creates a tool without those parameters. |
| Saved handoff tool in the Dashboard | The Tools page exposes function parameters for the handoff tool. Save the tool and attach it to the outgoing assistant.                                                                                                                 |
| Standalone assistant in a live call | A destination can identify a saved assistant by `assistantId`, or provide an inline assistant. Verify the destination resolves in the call.                                                                                             |
| `/chat` API                         | Assistant destinations require a squad context with more than one assistant. A standalone assistant's handoff tool call can return a handoff result without activating its destination.                                                 |
| Dynamic destination                 | A `handoff-destination-request` webhook chooses the destination at runtime. Its returned destination can include context and extraction plans. See [Dynamic handoffs](/squads/handoff/destinations#dynamic-handoffs).                   |

To confirm a handoff, inspect the call or chat transcript for the outgoing handoff tool call and the next assistant's response. For calls, use `call.id` to correlate records and inspect `artifact.variableValues` for values retained in the call. The active conversation used by analysis may differ from the artifact after context filtering; set [`artifactPlan.fullMessageHistoryEnabled`](/assistants/call-recording) if you need the full cross-assistant message history in the call artifact.