---
title: "RunScenario"
method: POST
path: "/api/scenario/v1/run-scenario"
tags: ["ScenarioService"]
---

# RunScenario

`POST /api/scenario/v1/run-scenario`

## Request

- Base URL: `https://api.worldmonitor.app`
- URL: `https://api.worldmonitor.app/api/scenario/v1/run-scenario`
- Auth: one of:
  - API key in header `X-WorldMonitor-Key`
  - API key in header `X-Api-Key`
  - HTTP bearer

RunScenario enqueues a scenario job on scenario-queue:pending. PRO-gated. Async job pattern: a successful enqueue returns HTTP 202 Accepted with a Location header pointing at GetScenarioStatus; poll it (or the statusUrl body field) with the returned jobId until status is "done" or "failed". The scenario-worker (scripts/scenario-worker.mjs) pulls jobs off the queue via BLMOVE and writes results under scenario-result:{job_id}. Requires entitlement tier >= 1.

## Headers

- `Idempotency-Key` string

## Request body

- WorldmonitorScenarioV1RunScenarioRequest: RunScenarioRequest enqueues a scenario job on the scenario-queue:pending Upstash list for the async scenario-worker to pick up.
  - `scenarioId` string, required: Scenario template id — must match an entry in SCENARIO_TEMPLATES.
  - `iso2` string: Optional 2-letter ISO country code to scope the impact computation. When absent, use the bounded country/sector manifest in existing seed metadata. Missing or old manifest means unknown coverage.
  - `disruptionPct` integer: Physical scenarios only. Omitted preserves the template default; zero is valid.

## Response `202`

Accepted — scenario job enqueued. The body carries the job id (jobId), the initial status (always pending) and a poll URL (statusUrl); the Location header points at the same GetScenarioStatus endpoint. Poll it until status is done or failed.

- WorldmonitorScenarioV1RunScenarioResponse: RunScenarioResponse carries the enqueued job id. Clients poll GetScenarioStatus with this id until status is "done" or "failed". A successful enqueue returns HTTP 202 Accepted with a Location header pointing at GetScenarioStatus; treat any 2xx as success.
  - `jobId` string: Generated job id of the form `scenario:{epoch_ms}:{8-char-suffix}`.
  - `status` string: Always "pending" at enqueue time.
  - `statusUrl` string: Convenience URL the caller can use to poll this job's status. Server-computed as `/api/scenario/v1/get-scenario-status?jobId=<job_id>`. Restored after the v1 → v1 sebuf migration because external callers may key off this field.

## Other responses

- `400`: Validation error, invalid Idempotency-Key header, or malformed JSON request body
- `401`: Missing or invalid API key.
- `403`: PRO entitlement access denied.
- `409`: A request with this Idempotency-Key is still being processed
- `422`: The Idempotency-Key was already used with a different request body
- `429`: Rate limit exceeded.
- `503`: Service unavailable. Billing-verification responses include code and X-Billing-Verification; other gateway infrastructure failures use the generic GatewayError shape.
- `default`: Gateway or handler error response.

---

[API](https://skmtc.dev/worldmonitor/apis/worldmonitor-api.md) · [All operations](https://skmtc.dev/worldmonitor/apis/worldmonitor-api/llms.txt) · [OpenAPI document](https://skmtc.dev/worldmonitor/apis/worldmonitor-api/revisions/e3dc8463a5c9?raw)
