Documentation

Webhooks & reconciliation.

Webhooks make the bridge fast. Reconciliation makes it correct. A verified delivery can wake work — it can never be the reason a write happens.

On this page The model Linear deliveries Todoist deliveries Delivery identity & limits Wakeups Reconciliation The outbox The repair pass

The model

Webhook payloads never directly become provider mutations. A verified event only wakes reconciliation, which rereads authoritative snapshots from both providers before any operation is planned. Unknown event types are persisted for the record but cannot mutate links or trigger writes.

Linear deliveries

  • When you connect Linear, TaskBridge registers a webhook for your workspace through Linear’s API — one per connection, with that connection’s own signing secret. There is nothing to configure by hand.
  • Deliveries arrive at POST /webhooks/linear/<connectionId> and are verified with that connection’s secret via the Linear-Signature HMAC over the exact raw body, then cross-checked against the connection’s workspace.
  • The signature timestamp is bounded by a replay window of 60 seconds by default.
  • Known issue events advance a durable per-issue cursor — including before a task link exists — so new issues wake reconciliation while stale, out-of-order deliveries do not.

Todoist deliveries

  • Todoist webhooks are delivered app-wide to POST /webhooks/todoist and verified with an HMAC over the exact raw body using the application’s client secret.
  • Each delivery is routed to the owning connection by the payload’s Todoist user id.
  • The payload’s triggered_at must be present and within a replay window of 5 minutes by default; events without a valid, bounded triggered_at are rejected before persistence.
  • Versioned and versionless events advance cursors monotonically — stored timestamps and link effects never move backward.

Delivery identity & limits

  • Both integrations use a hash of the verified exact raw body as the durable delivery identity. Caller-controlled delivery headers (such as Linear-Delivery) are never authoritative and cannot change uniqueness.
  • Raw webhook payloads are limited to 256 KiB by default.

Wakeups

A newly accepted known Linear event, or a Todoist event that advances a linked task cursor, wakes an asynchronous apply reconciliation. Wakeups are serialized and coalesced: at most one apply pass runs in the process, and an event arriving during a pass guarantees exactly one follow-up pass. Duplicate, stale, rejected, and unknown events do not create redundant passes.

Reconciliation

  • Reconciliation reads both systems, creates an explicit operation plan — create, update, complete, reopen — and applies nothing unless apply is explicitly true. Dry runs are always available and may overlap; apply passes are serialized per bridge under a per-bridge lock.
  • Every run is recorded in the bridge’s activity ledger with its trigger (activation, provider event, manual sync, scheduled check), mode, status, and exact result — including “No changes”.
  • Manual Sync now is throttled to once per 60 seconds per bridge.

The outbox

External mutations execute only after an atomic claim of a due outbox entry. Before touching a provider, every delayed operation:

  • verifies that its durable link id, Linear issue id, and Todoist task id still name one active relationship;
  • rereads the relevant providers and discards itself if generations are stale, so an old retry can never overwrite a newer edit;
  • skips the mutation when the target is already in the desired state.
  • Each apply pass drains at most 25 globally due entries, including retryable failures and expired claims.
  • Processing claims use a 120-second lease — deliberately longer than the 15-second provider timeout.
  • Retryable failures retain an exact next-attempt time; terminal failures have none and are reported, not retried forever.
  • Todoist create retries reuse a request id derived from the durable deduplication key, so a retried create cannot duplicate a task.

The repair pass

Correctness never depends on a webhook arriving. An in-process periodic pass reconciles each active bridge every 5 minutes by default, covering missed deliveries, process restarts, and due outbox retries. A missed webhook delays a change; it never loses one.