request
request controls how the HTTP request body becomes data and metadata, on HTTP ingresses only. Kafka parses the whole payload as data and builds metadata separately. channel_call inherits the parent’s metadata with data from the task input, so neither is affected.
Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
body_mode | string | no | "auto" | auto detects the Orion envelope; payload takes the parsed body verbatim. |
cookies_to_metadata | array of strings | no | — | Named request cookies copied to metadata.cookies.*. Absent exposes nothing. |
Under auto, an object carrying a top-level data or metadata key is the envelope: that key becomes the payload and every sibling field is discarded. Anything else (an array, a scalar, an object without those keys) is the payload as it stands, and an empty body is {}.
That rule keys on a field name. A request model that owns the name data — the standard FCM/push payload shape, among others — is read as an envelope. It loses its siblings silently, with a normal 200. payload mode is the opt-out:
{
"config": {
"request": { "body_mode": "payload" }
}
}
The two modes differ for exactly one input shape: a top-level object carrying data or metadata. Everything else already took the payload path in both.
Three consequences worth knowing before switching a channel:
- A caller cannot supply
metadataat all inpayloadmode — the metadata object is server-stamped keys only (channel,http_method, andparams/query/headerswhere applicable). Underauto, a caller-suppliedmetadata.paramsormetadata.querysurvives when the server has none of its own to stamp, so this is a small security win as well as a trade-off. - Downstream, consistently:
validation_logicsees the whole body underdata, andcache.cache_key_fieldspaths resolve against it. HMAC signing is unaffected — it always signed the raw bytes. orion-cli sendneeds--rawfor a payload-mode channel. The CLI wraps its argument in{"data": …}by default, which a payload-mode channel then delivers asdata = {"data": …}.orion-cli send my-channel --raw -d '…'sends the payload verbatim. Because such a channel accepts no caller metadata,--rawand--metadataare refused together rather than one being dropped.
Warning
Flipping a live channel from
autotopayloadchanges its wire contract for any caller currently sending a legitimate{"data": …}envelope — that envelope becomes the payload, so the workflow starts readingdata.data.*. It is a config change with the blast radius of a code change.
Reading request cookies
The Cookie header is masked to "******" before request metadata is built, along with authorization, proxy-authorization and x-api-key. The metadata map is persisted verbatim into traces.result_json and trace_dlq.metadata_json, so a plaintext value there is a plaintext credential at rest.
Not every cookie is a credential, though. cookies_to_metadata names the ones a workflow may read:
{
"config": {
"request": { "cookies_to_metadata": ["browser_uuid"] }
}
}
and then, in any task or in validation_logic:
{ "var": "metadata.cookies.browser_uuid" }
A listed-but-absent cookie is not present: never null, never an error. The raw Cookie header stays masked: this allowlist is additive and never unmasks it. metadata.cookies is platform-reserved, stamped from the allowlist and stripped otherwise, so a caller cannot supply it in an envelope.
Scope it to opaque identifiers a workflow matches against its own stored state: a browser-pinning id, a first-party visitor id, a bucket cookie. For a session token, JWT or CSRF token use auth.mode: "jwt" with source: {"cookie": …} instead. There the token is consumed at verification rather than copied into the context.
Warning
Allowlisted values land in
traces.result_jsonandtrace_dlq.metadata_jsonunmasked. The read side is covered —GET /admin/traces/{id}strips all ofcontext.metadata, but the row on disk is not. Note also thattracing.mode = "off"suppresses only sync persistence: on an/asyncchannel the row is still written before the202, so turning tracing off is not a complete mitigation there.trace_queue.retention_hoursis the ageing-out control.
Two further limits worth knowing:
- A cookie-varying channel must not enable
cache.compute_cache_keyhashes method, params, query and payload — never headers, so a cached response would replay one caller’sSet-Cookieto the next. rate_limit.key_logicstill cannot see cookies. Its context is{client_ip, channel, headers}, andcookieis not among the readable headers. Per-cookie rate limiting stays out of reach. It cannot see the authenticated principal either, because it runs before authentication —principal_rate_limitis the block that can.
channel_call propagates metadata verbatim, so an allowlisted cookie reaches sub-channels — the same way verified claims do.
Related
- Data API › Request body: the envelope the
automode detects. orion-cli send: the--rawflag a payload-mode channel needs.- Traces and async processing: where allowlisted cookies land on disk.
auth: thejwtmode with a cookie source, for session tokens.- Channel configuration: every key, with its page.
Last verified 14 September 2026