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

# RunScenario

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



## OpenAPI

````yaml /api/worldmonitor.openapi.yaml post /api/scenario/v1/run-scenario
openapi: 3.1.0
info:
  title: WorldMonitor API
  description: >-
    Unified OpenAPI bundle spanning all WorldMonitor services. Versioning and
    deprecation policy: https://www.worldmonitor.app/docs/api-versioning
  contact:
    name: WorldMonitor
    email: support@worldmonitor.app
  version: 1.0.0
servers:
  - url: https://api.worldmonitor.app
security:
  - WorldMonitorKey: []
  - ApiKeyHeader: []
paths:
  /api/scenario/v1/run-scenario:
    post:
      tags:
        - ScenarioService
      summary: RunScenario
      description: >-
        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.
      operationId: RunScenario
      parameters:
        - name: Idempotency-Key
          in: header
          description: >-
            Optional client-generated idempotency key. Retrying a POST with the
            same key and an identical request body replays the original response
            (only the status, body, and Content-Type are reproduced) instead of
            re-executing; reusing the key with a different body is rejected with
            422. For mutations this avoids duplicating the side effect, while
            for batch-read POSTs it replays a cached snapshot that can be up to
            24 hours stale. Keys are scoped per authenticated caller (falling
            back to the source IP for unauthenticated endpoints) and retained
            for 24 hours.
          required: false
          example: 4f8b9c2e-1a3d-4b6f-8e0a-2c5d7f9b1e34
          schema:
            type: string
            minLength: 1
            maxLength: 255
            pattern: ^[\x21-\x7E]{1,255}$
      requestBody:
        content:
          application/json:
            example:
              iso2: US
              scenarioId: hormuz-tanker-blockade
            schema:
              $ref: '#/components/schemas/worldmonitor_scenario_v1_RunScenarioRequest'
        required: true
      responses:
        '202':
          description: >-
            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.
          headers:
            Idempotency-Key:
              schema:
                type: string
              description: >-
                The idempotency key echoed from the request. Present only when
                the client opted into idempotency.
            Idempotent-Replayed:
              schema:
                type: boolean
              description: >-
                true when this response was replayed from an earlier request
                with the same key, false on the first (original) request.
                Present only when the client opted into idempotency.
            Location:
              schema:
                type: string
              description: >-
                Relative URL of the job-status poll endpoint for this job (same
                value as the statusUrl body field).
              example: >-
                /api/scenario/v1/get-scenario-status?jobId=scenario%3A1717200000000%3Aabcd1234
          content:
            application/json:
              example:
                jobId: scenario:1717200000000:abcd1234
                status: pending
                statusUrl: >-
                  /api/scenario/v1/get-scenario-status?jobId=scenario%3A1717200000000%3Aabcd1234
              schema:
                $ref: >-
                  #/components/schemas/worldmonitor_scenario_v1_RunScenarioResponse
        '400':
          description: >-
            Validation error, invalid Idempotency-Key header, or malformed JSON
            request body
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - type: object
                    required:
                      - error
                      - message
                    properties:
                      error:
                        type: string
                      message:
                        type: string
                  - $ref: '#/components/schemas/InvalidRequestBodyError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: PRO entitlement access denied.
          headers:
            X-Billing-Verification:
              description: >-
                Present when the 403 is a billing-provider-confirmed
                subscription lapse (value subscription_lapsed, matching the body
                `code`).
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '409':
          description: A request with this Idempotency-Key is still being processed
          headers:
            Idempotency-Key:
              schema:
                type: string
              description: The idempotency key supplied by the client.
            Retry-After:
              schema:
                type: string
              description: Seconds to wait before retrying the in-flight request.
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - message
                properties:
                  error:
                    type: string
                  message:
                    type: string
        '422':
          description: The Idempotency-Key was already used with a different request body
          headers:
            Idempotency-Key:
              schema:
                type: string
              description: The idempotency key supplied by the client.
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - message
                properties:
                  error:
                    type: string
                  message:
                    type: string
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        '503':
          description: >-
            Service unavailable. Billing-verification responses include code and
            X-Billing-Verification; other gateway infrastructure failures use
            the generic GatewayError shape.
          headers:
            Retry-After:
              description: Seconds to wait before retrying (1-60).
              schema:
                type: string
            X-Billing-Verification:
              description: >-
                Billing-verification state that produced this response (matches
                the body `code`).
              schema:
                type: string
            X-Validation-Mode:
              description: >-
                Present with value degraded when user API-key validation is
                temporarily unavailable.
              schema:
                type: string
            X-RateLimit-Mode:
              description: >-
                Present with value degraded when a fail-closed rate-limit
                dependency is unavailable.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/BillingVerificationError'
                  - $ref: '#/components/schemas/GatewayError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
      security:
        - WorldMonitorKey: []
        - ApiKeyHeader: []
        - BearerAuth: []
components:
  schemas:
    worldmonitor_scenario_v1_RunScenarioRequest:
      type: object
      properties:
        scenarioId:
          type: string
          maxLength: 128
          minLength: 1
          description: Scenario template id — must match an entry in SCENARIO_TEMPLATES.
        iso2:
          type: string
          pattern: ^([A-Z]{2})?$
          description: |-
            Optional 2-letter ISO country code to scope the impact computation.
             When absent, v1 computes only the seeded reporter set:
             US, CN, RU, IR, IN, TW.
      required:
        - scenarioId
      description: |-
        RunScenarioRequest enqueues a scenario job on the scenario-queue:pending
         Upstash list for the async scenario-worker to pick up.
    worldmonitor_scenario_v1_RunScenarioResponse:
      type: object
      properties:
        jobId:
          type: string
          description: Generated job id of the form `scenario:{epoch_ms}:{8-char-suffix}`.
        status:
          type: string
          description: Always "pending" at enqueue time.
        statusUrl:
          type: string
          description: |-
            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.
      description: |-
        RunScenarioResponse carries the enqueued job id. Clients poll
         GetScenarioStatus with this id until status != "pending".

         NOTE: a successful enqueue returns HTTP 202 Accepted with a Location
         header pointing at GetScenarioStatus — the legacy (pre-sebuf) contract,
         restored. The sebuf-generated server still emits 200 for every success
         (no per-RPC status-code annotation exists), so the gateway upgrades the
         status via the setSuccessStatusOverride side-channel
         (server/_shared/response-headers.ts). Treat any 2xx as success; the
         interim guidance to branch on response body shape instead of the status
         code remains valid.
    ValidationError:
      type: object
      properties:
        violations:
          type: array
          items:
            $ref: '#/components/schemas/FieldViolation'
          description: List of validation violations
      required:
        - violations
      description: >-
        ValidationError is returned when request validation fails. It contains a
        list of field violations describing what went wrong.
    InvalidRequestBodyError:
      type: object
      description: Returned when a JSON POST request body is empty or malformed.
      properties:
        message:
          type: string
          description: Invalid request body
      required:
        - message
    UnauthorizedError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message.
      required:
        - error
      description: >-
        Returned when the API key is missing, malformed, or lacks current API
        access.
    ForbiddenError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable entitlement failure reason.
        code:
          type: string
          enum:
            - subscription_lapsed
          description: >-
            Machine-readable denial code, present when the 403 is a
            billing-provider-confirmed subscription lapse (mirrored in the
            X-Billing-Verification response header).
        requiredTier:
          type: integer
          format: int32
          description: Minimum entitlement tier required for this endpoint.
        currentTier:
          type: integer
          format: int32
          description: Caller entitlement tier when known.
        planKey:
          type: string
          description: Caller plan key when known.
      required:
        - error
      description: >-
        Returned when a PRO-gated endpoint denies access because the caller has
        no resolved authenticated user, entitlements cannot be verified, or the
        caller lacks the required entitlement tier.
    Error:
      type: object
      properties:
        message:
          type: string
          description: Error message (e.g., 'user not found', 'database connection failed')
      description: >-
        Error is returned when a handler encounters an error. It contains a
        simple error message that the developer can customize.
    RateLimitError:
      type: object
      description: Returned when a gateway or handler rate limit rejects the request.
      properties:
        error:
          type: string
          description: Human-readable rate-limit failure reason.
      required:
        - error
    BillingVerificationError:
      type: object
      description: >-
        Returned with HTTP 503 when paid access cannot be confirmed right now:
        the billing provider is re-verifying a recently expired subscription, or
        the entitlement backend is unreachable. Retryable — honor Retry-After.
      properties:
        error:
          type: string
          description: Human-readable billing-verification failure reason.
        code:
          type: string
          enum:
            - renewal_verification_pending
            - renewal_verification_failed
            - entitlement_verification_unavailable
          description: >-
            Machine-readable billing-verification state, mirrored in the
            X-Billing-Verification response header.
        requiredTier:
          type: integer
          format: int32
          description: >-
            Minimum entitlement tier required for this endpoint, when the denial
            came from a tier gate.
      required:
        - error
        - code
    GatewayError:
      type: object
      description: >-
        Returned by gateway infrastructure errors before an RPC handler runs,
        such as origin, routing, method, authentication, or quota checks.
      properties:
        error:
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
          description: Gateway error reason or structured gateway failure details.
      required:
        - error
    FieldViolation:
      type: object
      properties:
        field:
          type: string
          description: >-
            The field path that failed validation (e.g., 'user.email' for nested
            fields). For header validation, this will be the header name (e.g.,
            'X-API-Key')
        description:
          type: string
          description: >-
            Human-readable description of the validation violation (e.g., 'must
            be a valid email address', 'required field missing')
      required:
        - field
        - description
      description: FieldViolation describes a single validation error for a specific field.
  securitySchemes:
    WorldMonitorKey:
      type: apiKey
      in: header
      name: X-WorldMonitor-Key
      description: User-issued WorldMonitor API key.
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Alias header for the WorldMonitor API key (X-WorldMonitor-Key).
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer token: a Clerk-issued JWT for browser session flows, passed as
        Authorization: Bearer <token>.

````