HookGet Open dashboard

Transforming payloads per destination

Six declarative ops that reshape a delivery before signing — and why we never run your JavaScript.

In short

  • A transformation is an ordered list of steps on the endpoint; each step is one op.
  • Six ops: pick, omit, rename, set, unwrap, wrap. Paths are dot-separated.
  • Applied before signing, so the signature always covers the bytes that arrive.
  • A failing transformation dead-letters — it never delivers the untransformed body.

What it is for

Three cases cover almost every real use. Stripping a field one destination must not see. Flattening our envelope for a receiver that wants its own shape. Tagging deliveries with a static field so the consumer can route them. All three are structural — none of them needs code.

The six ops

OpWhat it does
{"omit": ["data.customer.email"]}Removes paths. A missing path is a no-op, not an error
{"pick": ["type", "data.order.id"]}Keeps only the named paths — the body is rebuilt from them
{"rename": {"data": "payload"}}Moves a value to a new path
{"set": {"source": "hookget"}}Writes literal values (string, number, boolean, null) at paths
{"unwrap": "data"}The value at the path becomes the whole body
{"wrap": "event"}The whole body nests under this key

Setting one

On creation or with a PATCH; null clears it and deliveries go back to the body exactly as published:

curl -X PATCH https://api.hookget.com/v1/endpoints/ep_…   -H "authorization: Bearer $HOOKGET_KEY"   -d '{"transformation":[{"omit":["data.card"]},{"set":{"via":"hookget"}}]}'

Reshaping for a fixed-format receiver

A receiver that wants its own body, not our envelope — compose unwrap, pick and set:

[
  {"unwrap": "data"},
  {"pick": ["order.id", "order.total"]},
  {"set": {"source": "hookget"}}
]

Delivers {"order":{"id":…,"total":…},"source":"hookget"} — signed over exactly those bytes, so verification on the receiving side works unchanged.

The rules that keep it safe

  • It is never code. Svix and Hookdeck run customer JavaScript; we chose not to. A delivery worker that executes customer code is a worker whose blast radius is every other customer's traffic. Six structural ops cover the real cases with nothing to escape from.
  • Deterministic failures do not retry. The one runtime error is unwrap of a missing path. The same input fails the same way every time, so the delivery dead-letters immediately with transformation_failed instead of burning the schedule.
  • Never untransformed. If a transformation fails, nothing is delivered. An omit may exist precisely to strip a field that must not reach that destination — failing open would be a data leak.

If you genuinely need logic — conditionals, arithmetic, lookups — do it in your publisher before the event enters the pipeline, where it is your code on your terms. The comparison names who runs JavaScript per destination if that is a requirement.