Authored by clicking, shipped with the docs.
A scenario is a named, replayable sequence of requests — 100% declarative. There is no scripting hook anywhere, which is precisely what makes scenarios serializable, shareable and exportable. This guide is the authoring workflow, end to end; for what scenarios are and why, start at the feature page.
Capture, don’t write
Send a request in the try-it console, then “Add to a scenario”; the same action exists on any history entry. A scenario grows step by step out of requests that actually ran — at no point is there JSON to write by hand.
Chain by clicking the response
In the scenario view, the last response is clickable: click a key to turn it into a variable ({{petId}} ← /id) or an assertion. When a later step needs a variable no earlier step produces, the suggestion to extract one comes from the missing variable itself. Assertions come from the observed response or from the declared schema, the same way — by clicking.
Before anything is sent, the prerequisites panel answers “why will this fail”: missing variables, missing credentials, steps whose inputs nothing produces yet.
What a step can carry
Everything a step declares is data, never code — which is exactly what keeps scenarios serializable:
- Extractions — by pointer (
{{petId}} ← /id) or by a JSONPathquery(RFC 9535), where the first matched node wins. An extraction markedsensitiveis masked like any credential. One markedpersistis written into the active environment at the end of a successful run — deliberately allowed even underenvironmentsLocked, because the config governs the environment’s structure, not the values a run produces. - Assertions — four operators:
exists,equals(loose),regex(unanchored), andmatches— an RFC 9535 JSONPath that passes when it selects at least one node. timeout— per step, in milliseconds; the runner cancels the send past it.continueOnFailure— a failed step normally stops “Run all”; with this flag the sequence keeps going and the report names the steps that failed.- Inputs —
scenario.inputsdeclares named defaults; the environment overrides an input of the same name, and a value produced during the run overrides both.
Run it two ways
“Run all” unrolls the sequence and renders a per-step report — status, duration, extracted values, a history link per step. “Step by step” loads each step into the real try-it and lets the reader send it: an authored scenario becomes an interactive tutorial. In both modes, a missing variable blocks the step; the {{literal}} is never sent.
Ship it with the docs
Export the scenario as a JSON file, commit it, declare it:
{ "scenarios": [{ "id": "onboarding", "title": "Onboarding", "url": "/scenarios/onboarding.json" }] }Declared scenarios are read-only for the reader (“Duplicate” makes a local, editable copy) and load lazily, on open — except a pinned one, whose file is fetched when the home page loads. pinned: true features that scenario on the home page with its description and steps — typically the auth flow you want at hand on arrival. In multi-spec, declare scenarios only on specs[] entries: a scenario references operations of one specific spec.
A scenarios[] entry takes either the app’s own export format or an Arazzo workflow document (1.0 or 1.1), by url or as an inline document — so the file your CI already runs can be declared as it stands, and each of its workflows renders as a scenario:
{ "scenarios": [{ "id": "payments", "url": "/workflows/payments.arazzo.yaml" }] }Share it
A scenario travels as a JSON file or a #/scenario-import?d=… link. Import always shows a preview first and never runs anything automatically. A scenario file never contains a sensitive value — credentials stay environment {{var}}s, and stay home.
Local scenarios are capped at 200 per spec. Past the cap, creation is refused with an actionable message — export or delete first — never a silent eviction: a scenario is the reader’s work, not a cache.
Exchange Arazzo
Scenarios speak Arazzo, the OpenAPI Initiative’s workflow format: imports accept 1.0 and 1.1 documents, exports write 1.1.0 — steps, outputs, successCriteria, and $response.body#/id-style runtime expressions. One workflow of an imported document (JSON or YAML) becomes one scenario, and whatever the model cannot express is listed at import, never dropped silently — constructs the app cannot run (nested workflows, retry/goto actions, AsyncAPI steps) render with a “partial support” badge naming each.
The Export menu on a scenario page offers three take-aways: the scenario file, a share link, and the Arazzo document.
Hand it to your CI
Every scenario page carries an “Automate this scenario” panel: pick a runner and a CI platform, and it generates a ready-to-commit job that runs the scenario’s Arazzo document on a schedule — in someone else’s CI, with someone else’s runner. Two runners today, Redocly Respect (npx @redocly/cli respect) and Jentic’s Arazzo Runner (pip install arazzo-runner); two platforms, GitHub Actions and GitLab CI.
name: Create a payment
on:
workflow_dispatch:
schedule:
- cron: '0 6 * * *'
jobs:
create-a-payment:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Run the workflow
run: |
npx @redocly/cli@latest respect arazzo/create-a-payment.arazzo.json \
--workflow create-payment \
--input auth.token="$AUTH_TOKEN"
env:
AUTH_TOKEN: ${{ secrets.AUTH_TOKEN }}The job carries variable names wired to your CI’s secret store, never values — the panel lists the names to define and the snippet contains none of what your environment holds. A scenario declared by url generates a job that fetches the served document instead (curl -fsSL …): the file you own, nothing to commit and nothing to keep in step.
Before you copy anything, the panel names what might not survive the trip: Respect states it reads Arazzo 1.0.1, so a 1.1 document gets a version warning plus a per-construct one (the Selector Objects 1.1 extracts values with); Arazzo Runner states no revision, and the panel says exactly that instead of guessing. An authored document gets its own honest note — it may describe more than this documentation runs.
The panel works on your local scenarios too, not just declared ones. And the boundary is stated in the product itself: “This documentation stays a static page — it schedules nothing and runs nothing on your behalf.” The GitHub job wakes daily (0 6 * * * — edit the cron to taste); on GitLab, scheduling lives in CI/CD → Schedules. features: { "ci": false } removes the panel — the Arazzo export stays.
Or switch the whole thing off
features: { "scenarios": false } removes the feature entirely — nav section, capture buttons, home card, routes, search index. Local scenarios already in the reader’s browser stay in the database, intact, for the day it is re-enabled.