init.Tasks openapi.json inittasks.com

retries, auto-disable, and the poll you still need

Delivery and reconciliation

How a delivery is attempted

When a subscription is turned off

The delivery log

GET /v1/webhooks/{id}/deliveries lists one subscription's deliveries, newest first. It keeps every delivery still waiting, plus the last 100 that finished (delivered or failed), for 30 days.

A row is one delivery of one event, not one attempt:

field what it holds
id this delivery. A redelivery is a new row with a new id
eventId the event's id, the same on a redelivery
event the event type
status pending (waiting or between retries), delivered or failed
attempts how many attempts were made
responseStatus the HTTP status of the last attempt, or null if none answered
error why the last attempt failed, or why it was not sent
createdAt when the delivery was queued
deliveredAt when your endpoint accepted it
nextAttemptAt when the next attempt is due, or null

Only the last attempt is kept. To see the spacing of attempts, read your endpoint's own log.

POST /v1/webhooks/{id}/deliveries/{did}/redeliver queues the same event again, under the same event id.

At most 5,000 deliveries can wait for one subscription. Beyond that the oldest are closed as failed with the reason in error, and are still listed.

Limits

call limit
POST /v1/webhooks 20 created / hour / user. A refused URL does not use one
checking a URL (POST, or PATCH with url) 60 / hour / user, refused ones included
POST /v1/webhooks/{id}/ping 60 / hour / user
POST …/redeliver 60 / hour / user
subscriptions 25 per account

These windows slide: a slot frees one hour after it was used. Every /webhooks call also counts against your credential's request buckets and carries the RateLimit-* headers. See rate limits.

Inbound is best-effort

Inbound is best-effort and at-most-once. The change feed this API listens to makes one attempt per event and never retries, and its queue is not crash-safe. A dropped event is not detectable from either side.

Read that again before you design around it. It means webhooks are a latency optimisation, not a source of truth.

Reconcile on a timer

Keep a high-water mark and sweep with updated_since.

bash
curl -s "https://api.inittasks.com/v1/todos?updated_since=2026-09-15T17:00:00Z" \
  -H "Authorization: Bearer $INITTASKS_TOKEN"

Poll every few minutes and treat webhooks as the thing that usually makes the poll find nothing. Any integration that assumes every event arrives will be quietly wrong sooner or later, and quietly is the hard part.

Advance the mark only after the sweep has been processed. Advancing it first loses everything in the window if your handler dies.

See pagination and filtering for walking the pages a sweep returns.

Handling duplicates

A retry can deliver an event you already processed. Key on the event id from X-InitTasks-Event-Id and skip one you have seen. The id is the same on a retry, on a redelivery, and on every subscription of yours that hears about the same change.

Your reconciliation sweep will also re-deliver work the webhook already did. Make the handler idempotent and both problems go away at once.

Next