Create the webhook in Make
Start a new scenario whose first module is Webhooks → Custom webhook. Add a hook, name it after the form, and copy the URL Make generates. Leave the scenario open — in a moment it will want to learn the data's shape.
Give the hook to Postbag
Create a webhook Destination pointing at Make's URL. Honest description: Postbag posts JSON to any URL that will have it, and Make's custom webhook is exactly such a URL — no connector app, nothing version-locked.
form_id="fm_YOUR_FORM_ID" # Copy yours from: npx postbag forms list
destination_json="$(curl --fail --silent --show-error -X POST https://postbag.dev/v1/destinations \
-H "Authorization: Bearer pb_live_…" \
-H "content-type: application/json" \
-d '{
"type": "webhook",
"name": "Make",
"config": { "url": "https://hook.eu2.make.com/…" }
}')"
destination_id="$(printf '%s\n' "$destination_json" | jq -er '.id')"
printf 'Destination ID: %s\n' "$destination_id" form_id="fm_YOUR_FORM_ID" # Copy yours from: npx postbag forms list
destination_json="$(curl --fail --silent --show-error -X POST https://postbag.dev/v1/destinations \
-H "Authorization: Bearer pb_live_…" \
-H "content-type: application/json" \
-d '{
"type": "webhook",
"name": "Make",
"config": { "url": "https://hook.eu2.make.com/…" }
}')"
destination_id="$(printf '%s\n' "$destination_json" | jq -er '.id')"
printf 'Destination ID: %s\n' "$destination_id" Let Make learn the shape
Click Redetermine data structure (or Run once) so the webhook listens, then send a test through the Destination. Make catches it and maps the fields for its visual editor — your visitor's answers are the ones inside data.
curl --fail --silent --show-error -X POST https://postbag.dev/v1/destinations/"$destination_id"/test \
-H "Authorization: Bearer pb_live_…" curl --fail --silent --show-error -X POST https://postbag.dev/v1/destinations/"$destination_id"/test \ -H "Authorization: Bearer pb_live_…"
{
"id": "dl_a91x02",
"type": "submission.received",
"schema_version": 1,
"form": { "id": "fm_8f3kq2", "name": "Contact" },
"data": { "email": "[email protected]", "message": "hello" },
"extras": {},
"meta": { "received_at": "2026-09-09T12:00:00Z" }
} {
"id": "dl_a91x02",
"type": "submission.received",
"schema_version": 1,
"form": { "id": "fm_8f3kq2", "name": "Contact" },
"data": { "email": "[email protected]", "message": "hello" },
"extras": {},
"meta": { "received_at": "2026-09-09T12:00:00Z" }
} Route your Form to it
Tie the Form to the Destination, then build the rest of the scenario — a sheet, a CRM, an email chain, whatever Make is for in your house. Every new submission is stored before it's posted, and a failed post is retried up to ten times before it's left clearly marked for you.
route_body="$(jq -n --arg form_id "$form_id" --arg destination_id "$destination_id" \
'{ form_id: $form_id, destination_id: $destination_id }')"
curl --fail --silent --show-error -X POST https://postbag.dev/v1/routes \
-H "Authorization: Bearer pb_live_…" \
-H "content-type: application/json" \
-d "$route_body" route_body="$(jq -n --arg form_id "$form_id" --arg destination_id "$destination_id" \
'{ form_id: $form_id, destination_id: $destination_id }')"
curl --fail --silent --show-error -X POST https://postbag.dev/v1/routes \
-H "Authorization: Bearer pb_live_…" \
-H "content-type: application/json" \
-d "$route_body"