Return dynamic data from a mock API: UUIDs, timestamps & random values

Static mock responses get boring fast. Dynamic tokens let your webhook return a fresh UUID, the current timestamp, a random value, or an echo of the incoming request — computed at the moment each request is served.

A published Yellorn webhook returns whatever payload you stored — and by default that's a fixed string, the same bytes on every request. That's fine for a quick stub, but real clients want responses that vary: a fresh id per call, the current timestamp, a random amount, a status that flips between active and pending.

Dynamic tokens solve this. Wrap a small expression in {{ … }} anywhere in the payload and Yellorn evaluates it at the moment the request is served — so the response is computed live, per hit, without you redeploying anything.

Store this as a webhook payload:

{
  "id": "{{ uuid4() }}",
  "created_at": "{{ now() }}",
  "attempt": {{ randint(1, 5) }},
  "status": "{{ choice("active", "pending", "failed") }}",
  "caller": "{{ request.ip }}"
}

Every GET against the slug URL returns something like:

{
  "id": "0b5d1e94-2c1a-4f3e-9b8a-7d6c5e4f3a21",
  "created_at": "2026-06-25T01:00:50.842000",
  "attempt": 3,
  "status": "pending",
  "caller": "203.0.113.7"
}

…with a different id, attempt, status, and caller on the next request. The expression language is intentionally Python-flavourednow(), timedelta(days=1), randint(1, 9) — so it reads the way a Python developer expects.

  • Webhook response body (the /webhook/<slug> portal) — and these can echo the inbound request with {{ request.* }}.
  • Request Sender (/sender/<id>) — the request body, the URL, and header values. There's no inbound request to echo here, so the request.* tokens are hidden on this surface.

As the owner editing through the portal you always see the raw template ({{ now() }}), never a one-off rendered value — rendering only happens for public callers hitting the URL.

Date & time

  • {{ now() }} — ISO-8601 timestamp of the moment the request is served.
  • {{ now("%Y-%m-%d %H:%M:%S") }} — format the current time with a Python strftime pattern.
  • {{ today() }}, {{ timestamp() }} (Unix seconds), {{ timestamp_ms() }} (milliseconds).
  • Relative time {{ now() + timedelta(days=1) }} (tomorrow), {{ now() - timedelta(hours=2) }} (two hours ago). timedelta takes weeks, days, hours, minutes, seconds, milliseconds.
  • Datetime attributes & methods — {{ now().year }}, {{ now().date() }}, {{ now().isoformat() }}.

Identifiers

  • {{ uuid4() }} — a random RFC-4122 v4 UUID.
  • {{ objectid() }} — a 24-char hex Mongo ObjectId (timestamp + random).
  • {{ snowflake() }} — a 64-bit-style numeric, timestamp-ordered id.

Random values

  • {{ randint(1, 100) }} — integer in the inclusive range.
  • {{ randfloat(0, 1) }} — float in the half-open range.
  • {{ randstr(16) }} / {{ randhex(32) }} — random alphanumeric / hex strings.
  • {{ randbool() }}true / false at 50/50.
  • {{ choice("a", "b", "c") }} — one of the arguments, picked at random.

Echo the request (webhook only)

  • {{ request.method }}, {{ request.ip }}, {{ request.url }}, {{ request.path }}, {{ request.body }}.
  • {{ request.header("User-Agent") }} — a header value (case-insensitive).
  • {{ request.query("id") }} — a URL query-string parameter.

Strings, numbers, JSON

{{ int(x) }}, {{ str(x) }}, {{ upper(s) }}, {{ round(n, 2) }}, {{ min(…) }} / {{ max(…) }}, and {{ jsonstr(x) }} (JSON-encode a value with quotes + escapes).

The renderer substitutes a token's text form directly into the body, so what you put around the token decides the JSON shape:

// String value — wrap the token in quotes:
{ "at": "{{ now() }}" }        → { "at": "2026-06-25T01:00:50.842000" }

// Bare number — no quotes:
{ "n": {{ randint(1, 9) }} }   → { "n": 4 }

// Bare boolean:
{ "ok": {{ randbool() }} }     → { "ok": true }

When you echo untrusted request data into a JSON string, wrap it in jsonstr(...) so quotes, backslashes, and newlines are escaped and the document stays valid. jsonstr adds the surrounding quotes itself — don't also wrap it in literal "…":

{ "ua": {{ jsonstr(request.header("User-Agent")) }} }
// → { "ua": "Mozilla/5.0 (\"quoted\" UA)" }
  • Insert token picker — a searchable, categorised popover above the body field. Each row shows the snippet, a one-line description, and a live sample preview computed by the real engine, so the preview can never drift from reality.
  • In-editor autocomplete — start typing inside a {{ … }} token and a popover offers every builtin with its signature and a live sample value, inserting snippets with tab-stops so you can fill arguments by pressing Tab. Ordinary JSON / YAML editing outside a token is never interrupted.
  • Preview toggle — when the body contains a token, flip to Preview to render the whole body with deterministic sample values and see the response shape before publishing.
  • Two-phase validation — before a tokenized body is stored, Yellorn checks every token parses and that the rendered result still passes the format validator. A malformed token ({{ randint( }}) is rejected with a friendly message; the template is never stored broken.

A token that throws at render time keeps its literal {{ … }} in the output and is reported — it's always visible, never silently blanked, and one bad token can never break the public hot path.

Try a fix in the editor or browse more articles.