All docs
3 min read

Replay

A replay re-dispatches a webhook for a submission that's already happened. Same payload, same signing, fresh attempt counter.

When to replay

  • A bug in your handler dropped events. You shipped a fix; backfill.
  • Your downstream had an outage. The 7-attempt window expired before it recovered.
  • You added a new field to your processing logic and want history to flow through it.
  • You're debugging — you want to watch a known event hit a freshly-deployed endpoint.

One-click in the UI

  1. Form → Webhooks → click the webhook → Deliveries.
  2. Find the row.
  3. Click Replay.

The replay creates a new delivery row, completely independent from the original. Its retry counter starts at 1, so if it fails, the normal 7-attempt schedule kicks in.

You can also replay in bulk: filter the list (e.g. status=failed, date=last 24h), tick rows, Replay selected.

REST

POST /api/v1/deliveries/{delivery_id}/replay
Authorization: Bearer <token>

Returns the new delivery's ID:

{
  "delivery_id": "01HG10X4ZP7Q5NRM4VQ8WBCDEF",
  "status": "queued"
}

To replay every failed delivery for a webhook in a window:

POST /api/v1/webhooks/{webhook_id}/replay
Content-Type: application/json

{
  "status": "failed",
  "since": "2026-05-06T00:00:00Z",
  "until": "2026-05-07T00:00:00Z"
}

This queues replays in the background and returns a job ID you can poll.

MCP

formspring.replay_delivery(delivery_id)
formspring.replay_webhook(webhook_id, status="failed", since="2026-05-06")

Idempotency, again

A replay sends the same submission_id as the original. If your handler is idempotent (and it should be — see retries), the replay is a no-op when the event was already processed.

If your handler is not idempotent, a replay will double-process. We can't tell the difference between "you want to re-run this" and "you want this to count twice" — only you know. Make the handler safe and replays become risk-free.

What replay does NOT change

  • The signing secret. Same secret as the original delivery.
  • The payload. Bit-for-bit identical to what we sent the first time.
  • The submission. Replay is a delivery action; the submission record is untouched.

What replay DOES change

  • A new delivery_id.
  • A new X-Formspring-Timestamp header (current time).
  • A new HMAC signature (because the timestamp differs — but the body hash doesn't, since the body is identical and the signature is over the body).

If you're using the timestamp to reject stale messages (a good practice), a replay's timestamp is current — it won't get rejected as old.

What's next