# Event delivery behaviors This section helps you understand different behaviors to expect regarding how Featurebase sends events to your webhook endpoint. ## Retry behavior If a webhook delivery fails, Featurebase will automatically retry up to 3 times: | Attempt | Delay | | --- | --- | | 1st retry | 1 minute after the first attempt | | 2nd retry | 1 hour after the second attempt | | 3rd retry | 6 hours after the third attempt | A delivery is considered failed if: - Your endpoint returns a non-2xx status code - The request times out - A connection cannot be established ## Event ordering Featurebase doesn't guarantee that webhook events arrive in the order they were generated. For example, updating a post might generate the following sequence of events: 1. `post.created` 2. `post.updated` However, these events may not be delivered to your endpoint in that exact order. Your integration should not rely on receiving events sequentially, and it must be able to handle them regardless of arrival sequence. ## Handle duplicate events Webhook endpoints might occasionally receive the same event more than once. To prevent double-processing, log the unique event IDs that your endpoint has already handled. If a new incoming event's ID matches a previously processed event, skip it. ```json { "object": "notification_event", "topic": "post.updated", "id": "notif_0193a6e6-fb6b-78ef-b71f-15008d9f9cde" } ``` ### Example deduplication logic ```javascript const processedEvents = new Set(); function handleWebhook(payload) { // Check if we've already processed this event if (processedEvents.has(payload.id)) { console.log(`Skipping duplicate event: ${payload.id}`); return; } // Mark as processed processedEvents.add(payload.id); // Process the event processEvent(payload); } ``` > **Note:** In production, you should persist processed event IDs to a database rather than keeping them in memory. ## Quick response time Your endpoint should return a successful (2xx) status code promptly—before performing any lengthy operations that might lead to timeouts. ### Good pattern Return 200 immediately, then process: ```javascript app.post("/webhook", async (req, res) => { // 1. Return 200 OK right away res.status(200).send("OK"); // 2. Process the webhook asynchronously processWebhookEvent(req.body).catch((err) => { console.error("Webhook processing error:", err); }); }); ``` ### Bad pattern Wait for processing before responding: ```javascript app.post("/webhook", async (req, res) => { // Don't do this - it could timeout await processWebhookEvent(req.body); res.status(200).send("OK"); }); ``` This approach prevents timeouts and ensures Featurebase knows your endpoint received the event, even if processing takes longer. ## Webhook status Your webhook can have one of the following statuses: | Status | Description | | --- | --- | | `active` | Webhook is functioning normally | | `paused` | Webhook is manually paused by you | | `suspended` | Webhook has been automatically suspended due to repeated failures | If your webhook is suspended due to failures, you can reactivate it from your dashboard or via the Webhooks API after fixing the underlying issue.