Echolot
Requests

Dynamic values

Fill requests with values worked out at send time, such as timestamps, UUIDs, hashes, encodings, files and values from other requests and their responses.

A dynamic value is a token that Echolot works out each time the request is sent: the current time, a new UUID, a signature over the body, or a value from another request's latest response. You write it like a variable, with a $ in front: {{$uuid}}, {{$sha256('{{password}}')}}. Dynamic values work wherever variables do: the URL, parameters, headers, the body, form fields and auth fields.

This page shows how to add and edit them. Every dynamic value, with its arguments, is listed in the dynamic values reference.

Add one from the list

  1. In any field that takes variables, type {{. A list opens with the variables in scope first, then the dynamic values by category.
  2. Keep typing to narrow it: uuid, time, hmac. Each entry says what it gives.
  3. Move with ↑ and ↓ and press ↩ or ⇥ to insert it; Esc closes the list.

A value that takes arguments opens its editor as soon as you insert it, so you fill them in a form instead of typing them. To open the list without typing {{, right-click the field and choose Insert Variable or Value….

In the field, a dynamic value shows as a pill with a readable label: the value's title (HMAC-SHA256), or for a response value, the request and what it reads (Sign in › $.access_token). The text underneath stays as written.

Edit a token

Double-click a pill, or right-click it and choose Edit Token…. The token editor opens:

  • The button at the top says what the token is and changes it: a variable or a dynamic value.
  • The fields are the value's arguments. A request argument is a menu of the workspace's requests by folder; a query argument (a JSONPath, an XPath, a header name) has a button that lists what the latest response holds, so you can pick a value instead of typing its path.
  • Value shows what the token gives now, with the current environment, or Does not resolve with the current environment and why.
  • For a variable, Use Another Variable swaps it for another one, and Use a Response Value Instead turns it into a response value.
  • Remove deletes the token; Done keeps your changes.

Quick look

Rest the pointer on a pill to see what it gives without opening it: the value (masked for a secret, marked Secret), where it comes from, and how it is written. For dynamic values, quick look says when they are worked out: time and random values are Made again on every send; above is an example. Its buttons are Edit…, Copy Value and All Variables…, which opens the variables panel.

Writing them by hand

{{$name}}                       no arguments
{{$name('text', 42)}}           text in single or double quotes, numbers as they are
{{$base64(user)}}               a bare name is a variable
{{$base64('{{user}}:{{pass}}')}} variables inside text
{{$sha256("{{$requestBody('')}}")}} a dynamic value inside another one

A token inside a quoted argument must use the other kind of quote for its own arguments: double quotes around a token whose arguments are in single quotes, as in the last line.

What you can use

CategoryExamplesGives
Responses{{$response('auth/sign-in', '$.access_token')}}, {{$responseHeader('orders/create-order', 'Location')}}, {{$responseStatus('auth/sign-in')}}Values from another request's latest response.
Requests{{$requestHeader('', 'Content-Type')}}, {{$requestURL('auth/sign-in')}}, {{$requestJSONPath('', '$.lines[0].sku')}}Parts of this request (empty first argument) or another one, as they would be sent.
Encoding{{$base64('heidi:alpenglow')}}, {{$urlEncode('a b&c')}}, {{$jsonEscape('say "hi"')}}, {{$basicAuth('heidi', '{{password}}')}}, {{$jwt('{"sub": "heidi"}', '{{jwtSecret}}')}}, {{$newline}}Encoded or decoded text, escapes, a Basic auth value, a signed JWT.
Hashes and Signatures{{$sha256("{{$requestBody('')}}")}}, {{$hmacSha256('{{key}}', 'message', 'base64')}}, {{$md5('text')}}Hashes and HMACs, in hex unless you ask for base64 or base64url.
Time{{$timestamp}}, {{$timestampMs}}, {{$isoTimestamp}}, {{$httpDate}}, {{$date('yyyy-MM-dd', -86400, 'Europe/Zurich')}}The send time, in Unix seconds or milliseconds, ISO 8601, an HTTP date or your own format, moved by an offset in seconds and in a time zone.
Random{{$uuid}}, {{$randomInt(1, 6)}}, {{$randomString(16)}}, {{$randomHex(8)}}New random values on every send. $guid and $randomUUID are other names for $uuid.
Fake Data{{$randomFullName}}, {{$randomEmail}}, {{$randomCity}}, {{$randomPrice}}, {{$randomLoremSentence}}, {{$randomDatePast}}Made-up names, addresses, companies, prices, dates, lorem ipsum and more, new on every send, under Postman's names. The list groups them in submenus. See fake data.
Text{{$lowercase('{{name}}')}}, {{$uppercase('chf')}}, {{$trim('{{code}}')}}Text changed.
Files and System{{$file('data/order.json')}}, {{$env('HOME')}}A file's contents (a path relative to the workspace, or an absolute path), or an environment variable of the Echolot process.

$env isn't available to agents: when an AI agent sends a request, an environment variable of your Mac stays out of it.

The Alpenglow example uses one in Orders › Create order: its Idempotency-Key header is {{$uuid}}, so every order is new.

Values from other requests' responses

The Responses values read another saved request's latest response. The first argument is that request's path in the workspace, its folder and its name as in the files: auth/sign-in for Auth › Sign in.

ValueReads
$response(request, query)Anything, by the query's form: $.token (JSONPath), /feed/entry[1]/id (XPath), header:Location, cookie:session, regex:token=(\w+), jq:.data.token, keypath:data.items.0.id.
$responseJSONPath, $responseKeyPath, $responseJq, $responseXPath, $responseRegexThe body, with that kind of query. A regex gives its first group, if it has one.
$responseHeader, $responseCookieA header, or a cookie the response set.
$responseStatus, $responseBody, $responseBodyLengthThe status code, the body as text, its size in bytes.

When the request a value reads has no response yet, Echolot sends it first. The line under the URL bar says so before you send: Sends “Sign in” first. The optional last argument decides when that happens; in the token editor it is Send it first:

ArgumentIn the editorWhat happens
(none) or 'if-missing'When it has no response yetSends the other request only if it has no response.
'fresh'Every timeSends it before every send of this request (once per run in the Runner).
'latest'Never: use the latest responseNever sends it; uses its latest response.
{{$response('auth/sign-in', '$.access_token', 'fresh')}}

Requests that read each other in a circle are refused with the requests named.

To keep a value from a response in a variable that every request reads, rather than pointing at one request, use a response capture.

Values from this request

The Requests values read a request as it would be sent, with its variables and auth filled in. Leave the first argument empty for the request being sent: {{$requestHeader('', 'X-Request-Id')}}. Echolot works out only the part you ask for, so a header can sign the body:

X-Signature: {{$hmacSha256('{{signingKey}}', "{{$requestBody('')}}")}}

jq

jq filters work in $responseJq, $requestJq and $response(…, 'jq:…'), with nothing to install. A filter with several results gives them one per line:

{{$responseJq('catalog/list-products', '.items[0].sku')}}
{{$responseJq('catalog/list-products', '[.items[].price.amount] | add')}}

When a value doesn't resolve

A token that can't be worked out (a missing variable, a request with no response that can't be sent, a JSONPath that finds nothing) is sent as written, and the line under the URL bar shows 1 problem. Click it to see which. The token editor and quick look say the same.

On this page