Skip to main content

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 outbound Cookie header.
  • 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_file paths resolve relative to the .hen file.
  • body_file is only for ordinary HTTP requests.
  • GraphQL requires a ~~~graphql document block, and MCP, SSE, and WebSocket requests do not accept body_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.