Skip to content

Delivery and retries

Alfe stores every authentic event before it replies to the sender, so a 200 means the event is safe. Delivery is at-least-once, so design your agent’s handling to cope with an occasional repeat.

Your sender gets one of these:

Status Meaning What the sender should do
200 OK Alfe accepted the event. The body includes a deliveryId. Nothing.
401 Unauthorized The X-Alfe-Signature-256 header is missing or doesn’t match. Fix the signature. Don’t retry unchanged.
404 Not Found No active webhook exists at that URL. Stop sending.
413 Payload Too Large The body is over 256 KiB. Send a smaller body.
500 Internal Server Error Alfe couldn’t look up or verify the webhook. Retry later.
502 Bad Gateway The event was authentic, but Alfe couldn’t store it. Retry later.

A successful response looks like this:

Response
{ "received": true, "deliveryId": "wdl_01J9Z…" }

The body can be JSON or any other text. Alfe parses JSON when it can and passes anything else along as a string.

Alfe replies to the sender without waiting for your agent to finish. Then:

  • If your agent is online, Alfe delivers the event right away. It stays pending until the agent’s runtime accepts it, then becomes delivered.
  • If your agent is offline, the event waits. Alfe delivers it when the agent reconnects, so a restart or a network blip doesn’t lose events.

Waiting events expire after 24 hours, so a longer outage can lose them. If that matters, have your sender keep its own record so it can resend.

On terminal runtimes, events are recorded rather than pushed into a conversation. See What happens when an event arrives.

The same event can arrive twice, for example when a sender retries because it didn’t see your 200 in time. Alfe filters out a repeat when the request carries a stable ID.

It looks for these headers first:

  • X-GitHub-Delivery
  • Svix-Id
  • Idempotency-Key
  • X-Webhook-Id and X-Delivery-Id
  • Ce-Id (CloudEvents)
  • X-Slack-Request-Id
  • X-Amz-Sns-Message-Id (Amazon SNS)

If there’s no header, webhooks tagged stripe use the body’s id, and webhooks tagged slack use the body’s event_id.

A repeat gets a 200 and isn’t delivered again:

Response
{ "received": true, "duplicate": true }

Set Idempotency-Key when you send your own events, so retries are safe.

Even with duplicate filtering, an event can occasionally reach your agent twice, such as after a crash at the wrong moment. A request with no recognized ID also can’t be filtered. So a few habits help:

  • Make handling idempotent. Key the work on a stable field, such as an event ID, so running it twice does no harm.
  • Give your agent a clear instruction. Tell it how to recognize an event it has already handled.
  • Have your sender retry on errors. Retry on 500 and 502, but not on 401 or 404.