FileForms
Webhooks

Retries & Redelivery

The retry schedule, delivery inspection, and how to resend events manually.

What counts as a failed delivery

A delivery succeeds only on a 2xx response. Everything else is a failure and will be retried:

  • Any non-2xx status code
  • A redirect — deliveries never follow redirects
  • No response within 30 seconds
  • Connection or DNS errors

Retry schedule

After the initial attempt, failed deliveries are retried with increasing backoff:

AttemptDelay after previous failureTime since event (approx.)
1immediate
25 minutes5m
330 minutes35m
42 hours~2.5h
55 hours~7.5h
610 hours~17.5h
710 hours~27.5h

That's 7 attempts over roughly 27.5 hours. Retries run on a sweep every 5 minutes, so actual times can lag the schedule by up to 5 minutes. After the final attempt the delivery is marked failed and no further automatic attempts are made — but you can always redeliver manually.

Endpoints are never automatically disabled, no matter how many deliveries fail. To stop deliveries entirely, delete the endpoint.

Every delivery has a status: delivered, pending (automatic retries remain — shown as "Retrying" in the dashboard), or failed (retries exhausted).

Inspect deliveries

In the dashboard, Settings → Developers → Deliveries lists every event sent to your endpoints, filterable by endpoint, status, event type, and date. Click a row for the full payload, attempt history, response status, and the error returned by your endpoint.

The same data is available via the API:

curl "https://api.fileforms.com/v1/webhook-deliveries?status=failed&limit=50" \
  -H "x-api-key: sk_live_..."

Filters: endpoint, status (delivered | pending | failed), and type — each accepting a comma-separated list — plus from, to, order, limit (1–100, default 10), and cursor pagination via nextCursor.

Redeliver manually

Two operations, for two situations:

Resend specific deliveriesPOST /webhook-deliveries/resend with up to 100 event ids (or the Resend button on any delivery in the dashboard). Each event gets one immediate attempt with the same event id and payload (for document.uploaded events the fileUrl is freshly signed — see the event catalog), and the result is reported synchronously per event:

curl -X POST https://api.fileforms.com/v1/webhook-deliveries/resend \
  -H "x-api-key: sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "eventIds": ["evt_a1b2c3d4e5f6g7h8"] }'
{
  "results": [
    {
      "id": "evt_a1b2c3d4e5f6g7h8",
      "delivered": true,
      "responseStatus": 200,
      "responseError": null
    }
  ]
}

Resending works on any delivery — including already-delivered ones, which is useful while developing — and never affects the automatic retry schedule. Unknown event ids come back in results as failed rather than erroring the whole call.

Retry everything that failed for an endpointPOST /webhook-endpoints/{id}/retry-failed (or the Retry Failed button). Re-queues all undelivered events for that endpoint — both exhausted ones and ones still waiting on backoff — for the next automatic sweep, and returns { "queued": n }. Use this after fixing an outage on your side to catch up in bulk.

Send a test event

POST /webhook-endpoints/{id}/test with { "eventType": "filing.status_changed" } (or the Send Test button) sends a signed test delivery to that endpoint and reports whether it was delivered. The endpoint must be subscribed to the requested event type (400 otherwise). Test events match the real event shape exactly — same envelope (evt_ id, requested type, signature) and same data fields as the event catalog — with obviously fake sample values:

{
  "id": "evt_...",
  "type": "filing.status_changed",
  "createdAt": "2026-07-29T12:00:00.000Z",
  "data": {
    "orderId": "order_test0000000000000000",
    "orderType": "formation",
    "filingStatus": "filed",
    "filingDate": "2026-07-29T12:00:00.000Z",
    "createdAt": "2026-07-29T12:00:00.000Z",
    "subscriptionStatus": null,
    "exceptionCode": null,
    "exceptionReason": null,
    "exceptionMessage": null
  }
}

The sample ids don't resolve to real resources (a test document.uploaded event's fileUrl won't download anything), so use test events to develop your parser and verify connectivity and signatures — then place orders in the test environment to exercise the full flow.

On this page