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

# Edit a generated simulation suite

PATCH https://api.vapi.ai/eval/simulation/onboarding/suite/{suiteId}
Content-Type: application/json

Revise a suite created by `POST /eval/simulation/onboarding/suite`. Remove simulations, rewrite scenarios using natural-language instructions, or set `retryFailed` to regenerate scenarios that failed or exceeded generation limits. The response includes the updated suite and requirement coverage.

Requests can take up to 2 minutes.

Send a new `patchKey` for each edit. Replaying an applied key changes nothing and returns the current suite, with `failedEditSimulationIds` listing the simulations that edit could not rewrite, so retry a timeout or a 5xx with the same key. A suite remembers its last 50 keys, so never reuse one.

Each organization can make 60 edits per UTC day, shared with the dashboard. Requests that only remove simulations and replays of applied edits do not count toward this limit. On a 429 `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`, wait until the daily limit resets at 00:00 UTC before retrying.

Reference: https://docs.vapi.ai/api-reference/simulation-suites/simulation-onboarding-controller-suite-update

## Authentication

- `Authorization` header (bearer token, required) — Authenticate server-side requests with a private Vapi API key. Create or copy a key from the [Vapi Dashboard](https://dashboard.vapi.ai) and send it in the `Authorization` header as `Bearer <token>`. Keep private API keys out of client-side code and public repositories.

## Request

### Path parameters

- `suiteId` (string, required)

### Body (application/json)

This endpoint expects a SimulationOnboardingSuiteUpdateDTO.

- `patchKey` (string, required) — A new key for each edit. Replaying an applied key changes nothing and returns the current suite. A suite remembers its last 50 keys, so never reuse one.
- `removeSimulationIds` (list of string, optional) — Simulations to take out of the suite. They are unlinked, not deleted.
- `edits` (list of SimulationOnboardingSuiteEditDTO, optional) — Simulations to rewrite in place, at most one edit per simulation: put every change for a simulation in one instruction.
- `retryFailed` (boolean, optional) — Regenerate the scenarios that failed or did not fit when the suite was generated.

## Response

### 200

- `suite` (SimulationOnboardingSuiteRefDTO, required) — The generated simulation suite id and name.
- `assistantId` (string, required) — Assistant the suite is assigned to.
- `simulations` (list of SimulationOnboardingSuiteSimulationDTO, required) — The suite's simulations, in order.
- `coverage` (SimulationOnboardingSuiteCoverageDTO, required) — Counts of covered and total requirements, uncovered requirements, and scenarios available to retry.
- `requirements` (list of SimulationOnboardingRequirementDTO, required) — The test requirements used to generate the suite. Match their ids to `coverage.gaps` to identify uncovered requirements.
- `docs` (SimulationOnboardingSuiteDocsDTO, required) — Links to simulation testing best practices and tool mocking documentation.
- `reused` (boolean, required) — True when the request matched one already applied (same `idempotencyKey` or `patchKey`) and nothing changed.
- `failedEditSimulationIds` (list of string, optional) — Simulations an edit asked to rewrite that were not rewritten, for example because the rewrite did not generate in time. Retry them with a new `patchKey`.
- `toolGaps` (list of SimulationOnboardingToolGapDTO, optional) — Tool paths the suite's simulations do not exercise as configured, such as a tool mocked although it runs natively. Omitted when there are none.

## Errors

### 400 Bad Request Error

The body is invalid, or the edited suite uses something the org's data-region policy doesn't allow, so it isn't saved.

- `any`

### 403 Forbidden Error

The key can't edit simulation suites.

- `any`

### 404 Not Found Error

The suite wasn't generated by `POST /eval/simulation/onboarding/suite` in this org, or the org doesn't have API access to these endpoints yet.

- `any`

### 422 Unprocessable Entity Error

An MCP server's tools could not be listed, so simulations would call them for real instead of a mock. Check the server is reachable and retry.

- `any`

### 429 Too Many Requests Error

`SIMULATION_ONBOARDING_QUOTA_EXCEEDED`: the org made 60 edits today. Don't retry; the limit resets at 00:00 UTC.

- `code` (enum, required) — Which refusal this is. Retry `SIMULATION_ONBOARDING_GENERATION_IN_PROGRESS` with the same key and `SIMULATION_ONBOARDING_CONCURRENCY_LIMITED` or `SIMULATION_ONBOARDING_QUOTA_UNAVAILABLE` after `retryAfterSeconds`, send a new key for `SIMULATION_ONBOARDING_IDEMPOTENCY_KEY_REUSED`, and stop for `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`.
  - Allowed values: `SIMULATION_ONBOARDING_GENERATION_IN_PROGRESS`, `SIMULATION_ONBOARDING_IDEMPOTENCY_KEY_REUSED`, `SIMULATION_ONBOARDING_CONCURRENCY_LIMITED`, `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`, `SIMULATION_ONBOARDING_QUOTA_UNAVAILABLE`
- `message` (string, required) — What happened, written for the user.
- `retryAfterSeconds` (double, optional) — Seconds to wait before retrying, the same value as the `Retry-After` header. For a daily limit, the seconds until 00:00 UTC.
- `limit` (double, optional) — The daily limit that was reached, on a daily-limit refusal only.

### 502 Bad Gateway Error

The model failed to generate a usable result. Retry.

- `any`

### 503 Service Unavailable Error

Simulation generation is paused, no caller personalities are configured, or the quota store is unavailable for a private-key request. Quota outages return SIMULATION_ONBOARDING_QUOTA_UNAVAILABLE with Retry-After; retry with the same key.

- `SimulationOnboardingController_suiteUpdateRequestServiceUnavailableError`
  - SimulationOnboardingErrorDTO: SimulationOnboardingErrorDTO
  - SimulationOnboardingControllerSuiteUpdateRequestServiceUnavailableError1

### 504 Gateway Timeout Error

The edit took too long. Retry with the same `patchKey`.

- `any`

## Types

### SimulationOnboardingSuiteEditDTO

- `simulationId` (string, required) — Simulation in the suite whose scenario is rewritten.
- `instruction` (string, required) — Natural-language instructions for revising this simulation's scenario, such as "Have the caller ask for a refund after 30 days."

### SimulationOnboardingSuiteRefDTO

- `id` (string, required) — Suite id; pass it to edit or run the suite.
- `name` (string, required) — Suite name.

### SimulationOnboardingSuiteSimulationDTO

- `id` (string, required) — Simulation id; pass it back to edit or remove the simulation.
- `scenarioId` (string, required) — Scenario the simulation runs.
- `name` (string, required) — Scenario name.
- `successCriteria` (list of string, required) — Each success criterion, as the yes/no question it is judged by.
- `requirementIds` (list of string, required) — Requirement ids this simulation covers, e.g. `R3`.
- `mockedTools` (list of string, required) — Tools the scenario mocks.
- `personalityName` (string, optional) — Name of the simulated caller's personality.

### SimulationOnboardingSuiteCoverageDTO

- `covered` (double, required) — Requirements at least one simulation covers.
- `total` (double, required) — Requirements in the agreed draft.
- `gaps` (list of SimulationOnboardingCoverageGapDTO, required) — Requirements no simulation covers, and why.
- `retryable` (double, required) — Planned scenarios an edit with `retryFailed` would regenerate.

### SimulationOnboardingRequirementDTO

- `id` (string, required) — Stable requirement id, e.g. `R3`.
- `text` (string, required) — One observable behaviour the assistant must get right.
- `tag` (enum, optional) — Indicates an assumption, a requirement that needs a voice simulation, or a requirement that cannot be tested.
  - Allowed values: `assumption`, `not-testable`, `voice-only`
- `note` (string, optional) — What was assumed, why only a voice run can check it, or why it cannot be tested.

### SimulationOnboardingSuiteDocsDTO

- `bestPractices` (string, required) — Link to testing best practices.
- `toolMocks` (string, required) — Link explaining why tools are mocked by default.

### SimulationOnboardingToolGapDTO

- `toolName` (string, required) — Function name of the tool, e.g. `handoff_to_group_1` or `transferCall`.
- `reason` (enum, required) — Why the path is not exercised: a reason the simulations mock the tool, or why a native path is never reached. New reasons may be added.
  - Allowed values: `dynamic-handoff`, `destination-not-plain`, `destination-unresolved`, `destination-truncated`, `transfer-external`, `destination-name-unscoped`, `native-tool-shadowed`
- `assistantName` (string, optional) — Assistant the tool belongs to, when it is a handoff destination's tool. Unset for the assistant's own tools.
- `destinationNames` (list of string, optional) — Static destinations the simulations do not reach through this tool.

### SimulationOnboardingErrorDTO

- `code` (enum, required) — Which refusal this is. Retry `SIMULATION_ONBOARDING_GENERATION_IN_PROGRESS` with the same key and `SIMULATION_ONBOARDING_CONCURRENCY_LIMITED` or `SIMULATION_ONBOARDING_QUOTA_UNAVAILABLE` after `retryAfterSeconds`, send a new key for `SIMULATION_ONBOARDING_IDEMPOTENCY_KEY_REUSED`, and stop for `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`.
  - Allowed values: `SIMULATION_ONBOARDING_GENERATION_IN_PROGRESS`, `SIMULATION_ONBOARDING_IDEMPOTENCY_KEY_REUSED`, `SIMULATION_ONBOARDING_CONCURRENCY_LIMITED`, `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`, `SIMULATION_ONBOARDING_QUOTA_UNAVAILABLE`
- `message` (string, required) — What happened, written for the user.
- `retryAfterSeconds` (double, optional) — Seconds to wait before retrying, the same value as the `Retry-After` header. For a daily limit, the seconds until 00:00 UTC.
- `limit` (double, optional) — The daily limit that was reached, on a daily-limit refusal only.

### SimulationOnboardingControllerSuiteUpdateRequestServiceUnavailableError1

- `statusCode` (double, required)
- `message` (string, required)
- `error` (string, required)

### SimulationOnboardingCoverageGapDTO

- `requirementId` (string, required) — Requirement the gap is for, e.g. `R4`.
- `reason` (enum, required) — Why no simulation covers it. `failed` and `budget` gaps are regenerated by an edit with `retryFailed`.
  - Allowed values: `not-testable`, `unmapped`, `failed`, `budget`
- `detail` (string, optional) — A short explanation for the user.

## Examples

**Request**

```json
{
  "patchKey": "string"
}
```

**Response**

```json
{
  "suite": {
    "id": "string",
    "name": "string"
  },
  "assistantId": "string",
  "simulations": [
    {
      "id": "string",
      "scenarioId": "string",
      "name": "string",
      "successCriteria": [
        "string"
      ],
      "requirementIds": [
        "string"
      ],
      "mockedTools": [
        "string"
      ],
      "personalityName": "string"
    }
  ],
  "coverage": {
    "covered": 1.1,
    "total": 1.1,
    "gaps": [
      {
        "requirementId": "string",
        "reason": "not-testable",
        "detail": "string"
      }
    ],
    "retryable": 1.1
  },
  "requirements": [
    {
      "id": "string",
      "text": "string",
      "tag": "assumption",
      "note": "string"
    }
  ],
  "docs": {
    "bestPractices": "string",
    "toolMocks": "string"
  },
  "reused": true,
  "failedEditSimulationIds": [
    "string"
  ],
  "toolGaps": [
    {
      "toolName": "string",
      "reason": "dynamic-handoff",
      "assistantName": "string",
      "destinationNames": [
        "string"
      ]
    }
  ]
}
```