Guide
Transform Content-Type
Providers do not always send the body shape your receiver expects. A provider may send form data, nested JSON, or text while your destination expects application/json, or the reverse.
In FastHook, Content-Type conversion is a transformation concern. The source request stays stored as received; the connection branch returns a new outbound envelope with the headers and body your destination expects.
Attach the conversion only to the connection whose destination needs it. Other branches from the same source can keep the raw provider shape.
Where The Conversion Runs
Transformations run in the connection worker before FastHook creates the destination attempt. Set content-type in the returned headers and return the body in the shape that matches that header.
Do not treat this as a source setting. Source authentication, accepted request evidence, and replay input remain separate from the transformed destination payload.
When To Convert
- A provider sends application/x-www-form-urlencoded but your receiver expects JSON.
- A receiver expects a compact internal event envelope.
- One branch needs the original provider body while another needs normalized JSON.
- A legacy service requires a specific Content-Type header.
- You need to add metadata such as provider name or route name to the outbound body.
- A CLI or local receiver test proves the service parses the wrong body format.
Convert To JSON
The safest script returns a full request envelope. Preserve existing headers you still want, then overwrite content-type with application/json and return an object body.
If the inbound body is a string, parse it explicitly. If FastHook already stored an object body, reuse it directly.
addHandler("transform", (request) => {
const input =
typeof request.body === "string"
? Object.fromEntries(new URLSearchParams(request.body))
: request.body ?? {};
return {
...request,
headers: {
...request.headers,
"content-type": "application/json"
},
body: {
provider: "legacy-form-provider",
event_id: input.id,
event_type: input.type,
payload: input
}
};
});Convert To Form Or Text
Some legacy receivers expect form-encoded or text payloads. In that case, build the encoded body string and set a matching content-type.
Avoid setting content-length, host, connection, transfer-encoding, or other hop-by-hop headers. Let the delivery layer calculate transport headers from the final outbound body.
addHandler("transform", (request) => {
const body = request.body ?? {};
const form = new URLSearchParams({
event_id: String(body.id ?? ""),
event_type: String(body.type ?? ""),
provider: "legacy-provider"
});
return {
...request,
headers: {
...request.headers,
"content-type": "application/x-www-form-urlencoded"
},
body: form.toString()
};
});Branch-Specific Contracts
Create separate connections when different destinations need different content contracts. One destination can archive the raw provider payload, another can receive normalized JSON, and a legacy destination can receive form-encoded text.
- Name transformations after the destination contract, such as provider-to-app-json.
- Keep audit or storage destinations on the raw shape when needed.
- Keep idempotency fields in the converted body.
- Do not reuse one conversion for receivers with different parsers.
- If a destination verifies FASTHOOK_SIGNATURE, it verifies the final transformed payload.
Inspect The Delivered Shape
Debug content conversion from the source request outward. The stored request shows what FastHook received. Transformation executions show before-and-after event data. Attempts show what was sent to the receiver and what it returned.
If the receiver reports an empty body or wrong parser, inspect the attempt request headers and body before changing source settings.
curl "https://api.fasthook.io/v1/requests/req_xxx?include=data" \
-H "Authorization: Bearer fh_api_xxx" \
-H "x-team-id: tm_xxx"
curl "https://api.fasthook.io/v1/transformations/trs_xxx/executions?limit=20&dir=desc" \
-H "Authorization: Bearer fh_api_xxx" \
-H "x-team-id: tm_xxx"
curl "https://api.fasthook.io/v1/attempts?event_id=evt_xxx&order_by=created_at&dir=desc" \
-H "Authorization: Bearer fh_api_xxx" \
-H "x-team-id: tm_xxx"Common Mistakes
- Changing content-type without changing the body shape.
- Changing the body shape but leaving an old content-type header.
- Setting content-length manually.
- Putting conversion on a shared branch when only one destination needs it.
- Dropping provider event ids or idempotency keys during conversion.
- Debugging receiver code before checking the FastHook attempt payload.
- Replaying converted events before confirming the receiver is idempotent.