Execution options
One typed options object for timeouts, cost caps, cache, storage and logging, set per request, key, preset or workspace.
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.
{
"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
Options merge leaf by leaf, later layers winning:
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
| 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
| Option | Effect |
|---|---|
data.cache.* | The 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 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 |
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.
The full JSON Schema is public at GET /v1/options/schema. Workspace defaults are
GET / PUT /v1/options/defaults
and a key's defaults are PUT /v1/keys/{id}/options.