FLOWLOGIC
module /webhook-fundamentals

unit U33 of 4

Retry semantics

at-least-once delivery, dedup strategies

Webhook providers guarantee at-least-once delivery, not exactly-once. If your endpoint is slow, errors, or returns a non-2xx, the provider retries — often several times with exponential backoff. So the same logical event will sometimes arrive twice, or five times. Your pipeline must reach the same end state no matter how many copies land. That property is idempotency, and it’s non-negotiable for anything that writes to a CRM, sends an email, or charges a card.

The delivery id from U1 is your dedup key. Before acting, check whether you’ve already processed that id. A durable store — a database table, a Redis SET with a TTL, or the engine’s built-in store — records ids you’ve seen. First sighting: process and record. Repeat sighting: acknowledge with 200 and stop. Returning 200 on the duplicate matters; a non-2xx tells the provider to retry even harder.

Where it breaks: the slow endpoint. If real work runs before you respond, a provider timeout (often 3–5s) triggers a retry while your first run is still going — now two copies race. Respond 2xx immediately, then do the work behind the acknowledgement.

worked example

A dedup gate keyed on the delivery id, backed by a store with a TTL.

export const code = async (inputs) => {
  const id = inputs.headers['webhook-id'];
  const seen = await store.get(`evt:${id}`);        // durable KV, 24h TTL

  if (seen) {
    return { status: 'duplicate', id };               // caller returns 200, stops
  }

  await store.set(`evt:${id}`, '1', { ttl: 86400 });
  return { status: 'new', id };                       // continue the pipeline
};

field checklist

common failure — Double-charged from a retried delivery

A payment pipeline ran the charge before responding. The endpoint took four seconds, the provider timed out at three and retried, and the customer was billed twice. Two fixes stack: acknowledge with 200 before the charge so timeouts stop retrying, and gate the charge on the delivery id so even a genuine duplicate is a no-op.

check your understanding

You recognise a delivery id you have already processed. Which HTTP status should the endpoint return so the provider stops retrying it?

HTTP— acknowledged, already handled

next unit opens once this is passed

sandbox validation

The check above confirms you followed the unit. Marking the module COMPLETED takes more: build the automation in your own engine and submit the exported flow and its run evidence, signed, to your unique validation URL. See the module page for that spec.