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

# Chaining and postscripts

> Use captures and postscripts to pass IDs, tokens, and response values between API requests.

# Chaining and postscripts

Chaining lets one API step use data returned by an earlier step.

Use it for flows like login then fetch profile, create user then update user, or create order then verify order status.

## How chaining works

Every step in an API scenario can declare `captures`. A capture is a JSONPath into the response body plus a name for the value.

Later steps reference that name in headers, body, URL, query params, or any other string field. The runner substitutes the captured value when the request is sent.

A two-step login-then-fetch scenario, captured shape:

```json theme={null}
{
  "steps": [
    {
      "order": 1,
      "action": "login",
      "target": "${API_BASE_URL}/auth/login",
      "method": "POST",
      "body": { "email": "${AUTH_EMAIL}", "password": "${AUTH_PASSWORD}" },
      "captures": [{ "as": "token", "from": "$.access_token" }],
      "expectedStatus": 200
    },
    {
      "order": 2,
      "action": "fetch profile",
      "target": "${API_BASE_URL}/users/me",
      "method": "GET",
      "headers": [{ "key": "Authorization", "value": "Bearer ${token}" }],
      "expectedStatus": 200
    }
  ]
}
```

What is happening:

* Step 1 logs in. The capture `{ "as": "token", "from": "$.access_token" }` reads `access_token` off the JSON response body.
* Step 2 uses `${token}` in the `Authorization` header. The runner substitutes the captured value before the request fires.

You can capture anything addressable by JSONPath: a top-level field, a nested object, or an array element. Chain across as many steps as you need.

## Where you can use captured values

`${var}` interpolation runs on every string field of a step:

* Request body (raw, JSON, form-urlencoded, multipart).
* Headers.
* URL path and query params.
* Auth values (bearer token, API key).

The runner does plain textual substitution. There is no expression layer, so something like `Authorization: Basic ${user}:${pass}` will not produce valid Basic credentials. For Basic auth, use the structured `step.auth = { type: "basic", username, password }` shape and let the runner encode it.

## Environment variables

Two flavors of variable resolve at send time:

* **Captures** from earlier steps in the same scenario (`${token}`, `${userId}`).
* **Environment variables** from the active environment (`${API_BASE_URL}`, `${AUTH_EMAIL}`, custom values you've added).

Captures are scenario-scoped: they exist for the duration of the run, not across scenarios. Environment variables persist on the environment record and apply to every scenario you run against it.

Both use the same `${var}` syntax. The runner builds one merged map at send time and substitutes.

## Postscripts: writing values back to the environment

The API Playground supports declarative postscripts via the `postExtract` array on a saved request. After the response arrives, each rule runs and writes its captured value back into the active environment as a variable.

```json theme={null}
{
  "postExtract": [
    { "source": "body", "path": "$.access_token", "target": "AUTH_TOKEN" },
    { "source": "header", "path": "X-Request-Id", "target": "LAST_REQ_ID" }
  ]
}
```

Source decides where the rule reads from:

* `body` reads JSON via a small JSONPath subset.
* `header` reads a response header by name, case-insensitive.
* `status` reads the numeric HTTP status; `path` is ignored.

After a successful login request in the playground, the rule above writes `AUTH_TOKEN` into the environment. Every later request in the same environment that references `{{AUTH_TOKEN}}` or `${AUTH_TOKEN}` picks up the freshly captured value.

## When to use captures vs postscripts

* **Captures** belong on a scenario when one step's output feeds another step's input in the same run. They're scoped to the scenario and disappear after the run.
* **Postscripts** belong on a saved API Playground request when you want the captured value to persist across requests and across sessions, the playground equivalent of "save this token in my environment."

Both share the same JSONPath grammar.

## On the roadmap

<Tip>
  Pre-request and post-response scripts via a QuickJS sandbox (Playground phase 2) for arbitrary JavaScript transforms before send and after receive. OAuth2 (four grant types) with token caching that reuses the environment cached-bearer pattern. Per-request and per-folder variables in the scope stack so a folder can declare its own vars.
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="Scenarios" icon="list-checks" href="/api-testing-scenarios">
    See the full scenario shape captures attach to.
  </Card>

  <Card title="API Playground" icon="terminal" href="/api-testing-playground">
    Where postscripts live.
  </Card>

  <Card title="Auth profiles" icon="key" href="/api-testing-auth-profiles">
    Run the same scenario as multiple identities.
  </Card>

  <Card title="Request data generation" icon="sparkles" href="/api-testing-request-data-generation">
    How Qodex fills request bodies.
  </Card>
</CardGroup>
