Skip to content

Replay an event

Replay re-sends an already-captured event to a target of your choice. Use it to re-run a webhook after fixing your handler, or to move a captured event to a staging environment.

Terminal window
catchbin replay <event-id> --target http://localhost:3000

The event id comes from the dashboard or catchbin api events list. The captured method and body are preserved byte-for-byte. catchbin adds a few traceability headers to the outgoing request: X-Catchbin-Replay-Of: <event-id>, X-Catchbin-Replay-Mode: strip|resign, and a Catchbin-Replay user agent.

Terminal window
catchbin replay <event-id> --target http://localhost:3000 --strip

--strip removes the provider’s signature headers and sends the body unchanged. Use it for targets that do not verify signatures — typically local development.

Terminal window
catchbin replay <event-id> --target https://staging.example.com --resign

--resign computes a fresh signature for the target using the target environment’s signing secret. The secret is read from a hidden prompt so it never appears in your shell history or process list. For CI, pass it on stdin:

Terminal window
echo "$STAGING_WEBHOOK_SECRET" | catchbin replay <event-id> \
--target https://staging.example.com --resign --secret-from-stdin

The secret is used locally to sign and is then discarded — it is never stored by catchbin.

There are two ways to replay, and they behave differently:

  • CLI replay (above) fetches the event and POSTs it from your machine. It can reach localhost and your LAN, and it is not subject to the endpoint’s server-replay settings.
  • Server-delegated replay has catchbin’s backend do the POST. It reaches public targets only, is guarded against SSRF, and is audited. It is gated per endpoint by two independent flags, replay_from_dashboard and replay_from_api, both off by default. Turning either on is a step-up-authenticated settings change.

An event captured in metadata_only mode has no stored body, so it cannot be replayed. Events whose body was dropped for exceeding the size limit are refused for the same reason. A stored body stays replayable even if you later switch the endpoint to metadata_only.

If the target verifies signatures, replaying with --strip will be rejected (no signature) and replaying the original signature will be rejected (the signed timestamp is now old). --resign solves both by signing fresh for the target.