# Execution options (/docs/concepts/execution-options)



Every request that runs something (`call`, `run`, waterfall runs) accepts an `options` object.
The same object is the default for a workspace (Settings → **Options**), for an API key, and on a
preset.

```json
{
  "input": { "domain": "example.com" },
  "options": {
    "timing": { "timeout_ms": 8000, "deadline_ms": 30000 },
    "cost": { "max_cost_micro": 50000 },
    "data": { "cache": { "mode": "prefer", "max_age_s": 604800 } },
    "observability": { "log_level": "metadata" }
  }
}
```

## Precedence [#precedence]

Options merge leaf by leaf, later layers winning:

```text
built-in defaults < workspace defaults < key defaults < preset < request (headers, then body)
```

Arrays and scalars replace; objects merge. The built-in defaults are cache `prefer` with writes on,
stored records and bodies, `sync` delivery, and full logging with the live tail on.

Then the result is clamped to your plan:

| Plan | Max cache TTL | Max concurrency | Max retries | Max deadline |
| ---- | ------------- | --------------- | ----------- | ------------ |
| Free | 30 days       | 5               | 2           | 60 s         |
| Pro  | 180 days      | 25              | 3           | 120 s        |
| Team | 365 days      | 100             | 5           | 300 s        |

`log_level: none` becomes `metadata`, because every call is metered. A workspace that keeps no bodies
turns `full` into `metadata`.

`POST /v1/options/resolve` previews the result: the effective `options`, which layer set each leaf
(`sources`) and every path that was lowered (`clamped`). Every call's log row stores the options it
ran with.

## Headers [#headers]

| Header                                             | Option                                                               |
| -------------------------------------------------- | -------------------------------------------------------------------- |
| `X-Grid-Max-Cost: 0.05`                            | `cost.max_cost_micro` (the header is in USD; `0.05` is 50,000 micro) |
| `X-Grid-Preset: @slug`                             | `routing.preset`                                                     |
| `Idempotency-Key` (8–128 of `A-Z a-z 0-9 _ . : -`) | replays the first response for the same key and body                 |
| `Cache-Control: no-store`                          | skip the cache and do not write to it                                |
| `Cache-Control: no-cache`                          | refresh: call the vendor and overwrite the cached result             |
| `Cache-Control: only-if-cached`                    | answer from the cache or fail                                        |
| `Cache-Control: max-age=N`                         | accept cached results up to N seconds old                            |
| `Prefer: respond-async` / `Prefer: wait=N`         | asynchronous waterfall runs                                          |

Body `options` win over headers.

## What takes effect today [#what-takes-effect-today]

| Option                                                              | Effect                                                                                   |
| ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `data.cache.*`                                                      | The [private cache](/docs/concepts/private-cache) policy                                 |
| `data.store.records`, `data.store.bodies`                           | `false` stops cache writes, or stops storing request and response bodies                 |
| `data.fields`                                                       | Fields returned by `run` and waterfall runs when the body sets none                      |
| `timing.timeout_ms`                                                 | Per-attempt vendor timeout; caps every waterfall step                                    |
| `timing.deadline_ms`                                                | Deadline for a whole `run` or waterfall run                                              |
| `timing.retry.max`, `timing.retry.base_ms`, `timing.hedge_after_ms` | Waterfall step retries, backoff and hedging                                              |
| `concurrency.max_concurrency`                                       | Parallel steps in a waterfall stage                                                      |
| `cost.max_cost_micro`                                               | Spend cap for `call`, `run` and waterfall runs                                           |
| `routing.provider`, `routing.preset`                                | [Provider preferences](/docs/concepts/routing#provider-preferences) and preset for `run` |
| `identity.meta`                                                     | Meta tags (≤ 16 keys, values ≤ 500 characters) when the body has none                    |
| `observability.log_level`, `redact_fields`, `tail`                  | Body logging, masked keys, and whether the call shows on the live tail                   |

<Callout type="warn" title="Stored, not enforced yet">
  The schema also accepts `rate`, `delivery.mode`, `cost.daily_cap_micro`, `cost.dry_run`,
  `timing.schedule` and a few more. They validate, merge and are logged, and the editor marks them,
  but nothing acts on them yet.
</Callout>

The full JSON Schema is public at `GET /v1/options/schema`. Workspace defaults are
[`GET`](/docs/api/calls/options_defaults_get) / [`PUT /v1/options/defaults`](/docs/api/calls/options_defaults_put)
and a key's defaults are [`PUT /v1/keys/{id}/options`](/docs/api/access/keys_options_set).

