Skip to navigation

Simulations advanced

Mock tools, send lifecycle webhooks, set latency limits, and reuse structured outputs in simulations

Advanced simulation options let you set variable values, mock tool responses, trigger lifecycle webhooks, set latency limits, and reuse structured outputs. Use them after you complete the Simulations quickstart and need more control over behavior or test conditions.

How it works

Advanced options belong to each simulation in a suite. They control which values the assistant or squad receives, what mocked tools return, and which lifecycle events send webhooks.

Open a suite and select Edit, then Next. The review step contains the Success criteria, Variables, and Tool mocks & webhooks tabs.

Mock tool responses

During a simulation, the assistant or squad under test runs its real tools. Mock a tool to return fixed text instead, so that tool never calls its live service or API. A mock intercepts only the tool it names; every other tool the assistant or squad calls still runs for real.

On the review step, open Tool mocks & webhooks. Under Tool mocks, select Add, then configure each mock with three fields:

  • Tool: Select one of the tools configured on the assistant or squad. Only its configured tools, including Function tools, can be mocked.
  • Mock result: Enter the string returned in place of the tool’s live output.
  • Enabled: Toggle the mock on or off. A disabled mock is ignored, and the tool runs live.
Tool mocks section with a tool, mock result, and Enabled setting configured

The mock result is always passed to the assistant or squad as a string. In the Dashboard, enter plain text or JSON-formatted text directly. In a cURL JSON body, escape the quotation marks inside JSON-formatted text, as shown in the example. Use tool mocks to keep tool behavior deterministic, avoid side effects, and steer the conversation down a specific path without depending on a live service.

Common mock patterns

Choose a result that leads the assistant or squad through the behavior you want to test. These examples show how the result field appears in a cURL JSON body:

Return the data that the tool normally provides after a successful action:

{
"result": "{\"status\": \"success\", \"confirmationId\": \"APT-12345\"}"
}

These strings replace the selected tool’s output. They do not produce an HTTP error, add network latency, or cause a network timeout.

Send webhooks on run start and end

Turn on webhooks to notify your server when a simulation iteration starts or ends. Each webhook sends a POST request to the URL you configure.

On the Tool mocks & webhooks tab, under Webhooks, toggle Simulation start and Simulation end.

Webhooks section with Simulation start and Simulation end enabled

Vapi sends simulation.run.started when a simulation iteration begins. The example below is a voice payload. A chat payload omits the calls object:

{
"type": "simulation.run.started",
"simulationId": "8f2a9c1e-3b4d-4a7e-9c2f-1d6b0a5e7f34",
"runId": "b7d4e2a0-6c9f-4e13-8a52-2f7c9b1d4e60",
"simulationRunItemId": "c3e8f1a2-9d47-4b6c-8e30-5a1f2b9c7d84",
"iterationNumber": 1,
"isSimulation": true,
"calls": {
"testerCallId": "a1b2c3d4-...",
"targetCallId": "e5f6a7b8-...",
"listenUrl": "wss://..."
}
}

Vapi sends simulation.run.ended when the simulation iteration finishes. The example below is a voice payload. A chat payload omits calls, endedReason, and recordingUrl:

{
"type": "simulation.run.ended",
"simulationId": "8f2a9c1e-3b4d-4a7e-9c2f-1d6b0a5e7f34",
"runId": "b7d4e2a0-6c9f-4e13-8a52-2f7c9b1d4e60",
"simulationRunItemId": "c3e8f1a2-9d47-4b6c-8e30-5a1f2b9c7d84",
"iterationNumber": 1,
"isSimulation": true,
"calls": { "testerCallId": "a1b2c3d4-...", "targetCallId": "e5f6a7b8-...", "listenUrl": "wss://..." },
"endedReason": "...",
"canceled": false,
"failureReason": "...",
"startedAt": "2026-07-28T17:10:05.000Z",
"endedAt": "2026-07-28T17:12:30.000Z",
"transcript": "...",
"messages": [],
"recordingUrl": "https://..."
}

Both chat and voice payloads include simulationId, runId, simulationRunItemId, iterationNumber, and isSimulation. The ended event adds startedAt and endedAt, plus transcript and messages when you include them. The call-specific fields appear for voice simulations only: calls, endedReason, and recordingUrl. The calls object includes calls.listenUrl, a WebSocket URL for monitoring the run in real time. For the complete list of endedReason values, see Call ended reasons.

Reuse structured outputs

Each evaluation references a structured output. Reuse a structured output when several simulations should apply the same evaluation criterion. For more patterns, see structured output examples.

Reuse an existing structured output across simulations to keep the same criterion consistent, or create a new one inline from the Success criteria tab.

Set latency limits

A latency limit fails a voice simulation when the assistant or squad under test responds too slowly. Vapi measures latency on each turn of the call, combines the turns into one number, and passes the limit when that number is at or below the limit you set.

Latency limits work alongside structured-output evaluations. A scenario still needs at least one evaluation, and a required limit that fails marks the simulation as failed even when every evaluation passes.

On the Success criteria tab, under Latency expectations, select Add latency expectation. Configure each limit with four fields:

  • Aggregation: How the call’s turns are combined: Median, Mean, P95, or Max.
  • Metric: Turn latency, Model latency, or Voice latency.
  • Limit: The maximum in milliseconds, as a whole number from 1 to 60,000.
  • Required: Turn off to make the limit informational. An optional limit is reported but never fails the simulation.

A new limit starts as a required median turn latency of 1,200 ms. Each simulation can have up to 20 limits.

Metrics and aggregations

MetricWhat it measures
turnTotal time from the end of the AI tester’s speech to the start of the assistant’s reply
modelTime for the model to return its first token
voiceTime for the voice provider to return the first audio

The aggregation reduces the call’s turns to one value: mean, median, p95, or max. p95 uses the nearest-rank method, so on a call with fewer than 20 turns it equals max. Measured values are rounded to the nearest millisecond before they are compared with the limit.

Gate on median turn latency. A short simulation has only a few turns, so p95 and max can fail on a single slow turn. To watch the slowest turns without failing runs, add an optional p95 or max limit next to a required median limit on the same metric.

When a limit is skipped

SituationResult
The run uses chat modeSkipped. Chat runs have no audio, so there is no latency to measure.
The assistant under test uses GPT-LiveSkipped. Per-turn latency isn’t measured for GPT-Live assistants yet. A GPT-Live AI tester talking to a classic assistant is still measured.
A voice run where no turn measured the metricThe limit fails. A latency that couldn’t be measured never counts as within the limit.

Skipped limits don’t affect the result.

Review latency results

Open a run and select a simulation. The Latency section shows average turn latency when at least one turn was measured. Each limit shows its threshold and result. When at least one turn measured that limit’s metric, the result also shows the measured value and number of turns. Optional and skipped limits are labeled. When a simulation fails, the count in the results list, such as 1 of 3 evaluations failed, includes its latency limits.

Through the API, each run item’s results.latencyEvaluations holds one entry per limit with actualMs, thresholdMs, sampleCount, passed, required, and, for skipped limits, isSkipped and skipReason. results.passed accounts for required latency limits.

Set variable values for the assistant or squad

Variables provide values for the dynamic variables used by the assistant or squad during the simulation. On the Variables tab, add Name and Value pairs. Each name must match a {{variable}} placeholder in the assistant’s prompt, and the value is substituted during the run.

Use variables to test specific inputs, such as a customer name or account tier, without editing the assistant or squad.

Simulate a call from a specific phone number

Assistants that identify callers by phone number, for example by passing {{customer.number}} to an account lookup tool, need a known caller number to test against. Set customer.number in the scenario’s targetOverrides.variableValues. The Variables tab only accepts flat names, so set this value through the API:

curl -X PATCH "https://api.vapi.ai/eval/simulation/scenario/<scenario-id>" \
-H "Authorization: Bearer $VAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"targetOverrides": {
"variableValues": {
"customer": { "number": "+14155550123" }
}
}
}'

For a transient scenario, set the same targetOverrides on the inline scenario in POST /eval/simulation/run.

  • The value replaces the whole customer variable, so also set any other customer fields the assistant references, such as customer.name.
  • Only {{customer.number}} changes. The call.customer object in server messages does not, so a tool that reads the caller from the message payload won’t see the override.
  • To test the conversation without a real lookup, mock the tool instead.

Troubleshooting

IssueWhat to check
Every iteration failsReview the transcript, then verify the evaluation’s description, data type, comparator, and expected value.
A run stays queued or runningCheck the assistant or squad configuration and its provider credentials. Fetch the run and its items to find a failure reason.
Results vary between runsMake the intent and evaluations more specific, then run multiple iterations to measure consistency.
There is no audio or recordingCheck whether the run used chat mode. Use voice mode to test or record audio.
Start or end webhooks do not triggerConfirm the corresponding hook and its URL are configured on the scenario.
A tool mock does not applyConfirm that toolName matches the configured tool name exactly and that enabled is true.
A tool looks up the wrong callerSet customer.number in the scenario’s variable values. See Simulate a call from a specific phone number.
A latency limit fails without a measured valueNo turn in the call measured that metric. Confirm the run used voice mode and that the conversation completed at least one exchange.
Latency limits show as skippedCheck whether the run used chat mode or the assistant under test uses GPT-Live. Both skip latency limits.

Next steps