Requests and Bodies
Request Blocks
$ API_ORIGIN = https://api.example.com
---
Fetch user
GET {{ API_ORIGIN }}/users/123
^ & status == 200
& body.user.id -> $USER_ID
---separates the collection preamble from request blocks.- A request title names the block for output, dependencies, and captures.
- The target line, directives, mappings, captures, and assertions all stay in the same block.
Request Target
POST https://example.com/profile
If protocol is omitted, the request is ordinary HTTP.
Later session-backed requests may omit the method and URL line when the protocol supports target inheritance from an earlier step in the same session.
Headers
* header_key = header_value
* header_key = {{ variable_name }}
* header_key = [[ prompt_name ]]
Request-level headers override global preamble headers when the name matches exactly.
Use the same casing when overriding a global header. Case-only differences are not a reliable override.
Query Parameters
? query_key = query_value
? query_key = {{ variable_name }}
? query_key = [[ prompt_name ]]
Cookies
@ cookie_name = cookie_value
@ cookie_name = {{ variable_name }}
@ cookie_name = [[ prompt_name ]]
- Cookie directives are valid in the collection preamble and inside individual requests.
- Request-level cookies override preamble cookies when the cookie name matches exactly.
- Hen serializes structured
@ ...cookies into one outboundCookieheader. - Structured
@ ...cookies cannot be mixed with a manual* Cookie = ...header on the same request. - When a request also uses
session = ..., explicit@ ...cookies merge with the session cookie jar by name, and explicit request cookies win on conflicts.
For example:
@ region = us-east-1
---
Load dashboard
session = web
GET https://example.com/dashboard
@ session = [[ session_id ]]
Multipart Form Data
~ form_key = form_value
~ form_key = {{ variable_name }}
~ form_key = [[ prompt_name ]]
~ form_key = @/path/to/file
Request Body
~~~json
{"id":"123"}
~~~
body_file = @./files/raw_payload.bin
Use ~~~ [content_type] to define the body block. Protocol-specific authoring may tighten the
allowed body forms.
Use body_file = @path when you want to send raw bytes from disk, similar to
curl --data-binary @file.
For example:
~~~ application/json
{
"username": "[[ username ]]"
}
~~~
POST https://example.com/upload
body_file = @./files/raw_payload.bin
* Content-Type = application/octet-stream
body_filepaths resolve relative to the.henfile.body_fileis only for ordinary HTTP requests.- GraphQL requires a
~~~graphqldocument block, and MCP, SSE, and WebSocket requests do not acceptbody_file. - See Binary request bodies for a runnable example.
Common Directives
name = Example Collection
description = Basic request set
timeout = 30s
poll_every = 1s
session = web
protocol = graphql
These directives shape how Hen prepares and executes requests while staying in the same line-based authoring model.
Request titles, directives, mappings, captures, and assertions all live in the same request block, so authoring stays close to the behavior being validated.