Skip to content
Open beta — everything’s free right now, and your rate is locked when it ends.

The delivery ledger: every send, readable

Each webhook keeps a ledger of every delivery — payload sent, response received, status, duration. The retry schedule, the health chips, auto-pause after 20 straight failures, and Replay.

Updated August 2026

A webhook that fails silently teaches you to distrust automation. So every webhook's page ends in a ledger: one row per delivery, with the exact bytes sent, the exact response received, and what Tabla did about a failure. When someone asks "did the order hit the fulfillment system?", the answer is a row, not a guess.

The Deliveries ledger with one delivery expanded — the Delivered chip, try 1 of 4, the SENT payload JSON, the RESPONSE with its HTTP status and duration, and the Replay button.

Reading a row

Left to right: the status chip, the event (record.created, webhook.test, …), the record it was about — its display value, or the table name on a whole-database webhook — the attempt count when there's been more than one (try 2 of 4), the HTTP status your endpoint returned, the duration, and when. A delivery has one of four statuses:

  • Queued — waiting its turn, or scheduled for a retry.
  • Sending — a request is in flight right now.
  • Delivered — your endpoint answered 2xx. Final.
  • Failed — four attempts exhausted. Final, and the row grows a Replay button.

"Delivered" means exactly: any 2xx response within the 10-second request timeout. Redirects are not followed — a 3xx counts as a failure, so point the webhook at the final URL.

Click any row and it expands into the whole exchange: the attempt line (when, try N of 4, delivered time or next try in …), the error if there was one (connect ECONNREFUSED, a timeout, an HTTP status), then Sent — the full JSON payload, with a copy button — and Response, with your endpoint's status, duration, and the start of its body.

The retry schedule

A failed attempt is retried after 10 seconds, then 1 minute, then 5 minutes — four attempts in all, a little over six minutes end to end. An attempt that succeeds anywhere along the way ends it: the delivery is Delivered and nothing more is sent.

Watched live against a dead endpoint: a delivery created at 23:03:12 retried on schedule and reached Failed, try 4 of 4, at 23:09:50 with connect ECONNREFUSED recorded on the row.

The schedule exists to ride out restarts and blips, not outages. For a longer outage, the ledger plus Replay is the recovery path.

The webhook's own health

Above the ledger — and on the Webhooks list — each webhook wears one of five chips:

  • Not fired yet — created, no attempts.
  • Healthy — the last delivery succeeded.
  • Failing · N of 20 — N deliveries in a row have exhausted their retries. Any success resets the count to zero.
  • Paused — see below.
  • Off — the Active switch is off; a deliberate stop.

Auto-pause, and what Resume does

After 20 straight failed deliveries, the webhook pauses itself. Retrying into a dead endpoint forever helps nobody, and the pause is loud: a banner on the webhook's page — Paused after 20 straight failures. Nothing sends until resumed. — a Paused chip in the list, and a dot on the Webhooks tab itself, visible from the Data section.

Two things about a pause worth stating plainly:

  • Events during a pause are dropped, not queued. A paused (or switched off) webhook enqueues nothing; resuming starts from now. If your endpoint was down for a day, replay what the ledger holds — the events themselves don't accumulate behind the pause.
  • Resume is a clean slate. Clicking Resume clears the pause and resets the failure count to zero — you resumed because you believe the endpoint is fixed, so it isn't re-paused on the first hiccup.

Test sends never move any of this: a test is one attempt, never retried, never counted toward health.

Replay

Replay — on every failed row, and in every expanded row — queues a fresh delivery of that delivery's exact payload. It gets a new delivery_id, a fresh timestamp and signature, and the normal four-attempt retry schedule. Replay is how you recover after fixing an endpoint: fix, then replay the failures, newest last.

Replays (and tests) are editor-and-up actions — they cause real outbound traffic. Viewers can read the ledger but not send from it.

How long the ledger keeps

Deliveries are kept for 30 days, and a quiet webhook always keeps its most recent 200 regardless of age. The page shows the latest 50; the full stored set is readable over the API:

curl https://tabladb.com/api/webhooks/whk_wn6xcsbfk3by/deliveries \
  -H "Authorization: Bearer key_xxxx.your-secret"

Each entry carries the payload, status, attempt count, response status and body, duration, and error — the same facts the screen shows. For what's inside a payload, see webhook payloads; for making a failing endpoint verifiable, see verify signatures.

Tabla is the database we build these on.

A no-code database with real Postgres underneath: every feature on every plan, a million records per database, and your whole database back out in one file, any day.

More guides