Docs

Replay to localhost

Deliver a captured webhook to a local dev server, byte for byte, so signatures still verify.

Porch runs on the internet and can't reach your machine, which is the point. To get a captured request into a dev server on localhost, ask get_request for a replay recipe and run it locally.

Get the recipe#

get_request
{
  "inbox_key": "porch_sk_…",
  "request_id": "req_1",
  "replay_to": "http://localhost:3000/api/webhooks",
  "append_path": true
}

The result includes a replay object:

json
{
  "replay": {
    "curl": "curl -sS -i -X 'POST' -H 'content-type: application/json' -H 'stripe-signature: t=…' -H 'x-porch-replay: req_1' --data-binary '{\"type\":\"checkout.session.completed\",…}' 'http://localhost:3000/api/webhooks/stripe'",
    "method": "POST",
    "url": "http://localhost:3000/api/webhooks/stripe",
    "headers": { "content-type": "application/json", "stripe-signature": "t=…", "x-porch-replay": "req_1" },
    "body_base64": "eyJ0eXBlIjoiY2hlY2tvdXQuc2Vzc2lvbi5jb21wbGV0ZWQiLC4uLn0="
  }
}

Run it#

From a shell, run replay.curl on the machine that can reach the server. Binary bodies are piped through base64 -d, so the command works for any payload.

From code (including agents that run code against MCP tools), send replay.method to replay.url with replay.headers and the decoded bytes of replay.body_base64:

js
const res = await fetch(replay.url, {
  method: replay.method,
  headers: replay.headers,
  body: replay.method === 'GET' || replay.method === 'HEAD' ? undefined : Buffer.from(replay.body_base64, 'base64'),
})

Don't rebuild it by hand#

It's tempting to take the parsed json and post it again. Re-serializing changes key order, spacing and escaping, so HMAC signatures no longer match, and copying headers by hand tends to bring along Host and Content-Length values that break the request. The replay recipe avoids both.

The debugging loop#

  1. Trigger the real event once (a test payment, a push, a form submission).
  2. wait_for_request to capture it.
  3. Replay it to your local handler as many times as you need while you fix the code. There's no need to trigger the event again.

Captured requests are kept for up to 4 hours. Porch never sends requests anywhere itself.