hide_table_of_contents: false title: Best Practices For Webhooks sidebar_label: Best Practices custom_edit_url: null

Best Practices For Webhooks

1. Secure your webhook endpoint

  • Use HTTPS: We strongly recommend that your webhook endpoint registered with the Fynd Platform uses HTTPS. Encrypting communication with HTTPS ensures that data transmitted between the Fynd Platform provider and your server is secure. This prevents man-in-the-middle attacks where an attacker intercepts and potentially alters the data.
  • Implement Integrity Checks: We strongly recommend you validate the incoming request's HMAC (Hash-based Message Authentication Code) signature before processing the payload. This ensures that the payload is indeed from the Fynd Platform and not has been tampered or altered with. Each webhook request contains the x-fp-signature HTTP request header, which is calculated by the Fynd Platform using the following code:

<CodeBlock language="javascript" code={const { createHmac } = require('crypto'); const hmac = createHmac("sha256", "<secret-value>"); // this secret is obtained from your extension details page present in partner panel hmac.update(JSON.stringify(payload)); const hmacHex = hmac.digest("hex");}>

Before processing the webhook request, please calculate the HMAC using the same logic/algorithm and ensure that the resultant signature matches the value of `x-fp-signature` header.

<Admonition>
  The secret used for creating the HMAC can be obtained from going into you **[Partner panel](https://partners.fynd.com/organizations) → Extensions → your-extension → API Secret**.
</Admonition>
<img src="https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/original/image_(16).png" alt="QG1" style={{border: "1px solid #ccc;", borderRadius: "5px"}}/>

2. Ensure idempotency and handle retries

Fynd Platform's webhook system follows an "at least once delivery" semantics. This means that it is quite possible that the same webhook request may be sent to your webhook endpoint multiple times. Thus, it is strongly recommended that your webhook handler be written in an idempotent manner and be able to gracefully handle retries.

Idempotency

Design your webhook handlers to be idempotent. This means that receiving the same webhook request multiple times should have the same effect (on your side) as receiving it once. There are multiple ways to make this happen:

  • Most accurate (but cumbersome): The most accurate way to ensure that the webhook handler is idempotent is to identify a "marker" or a "trace" in your system that can help determine whether the webhook payload has already been processed or not. This will likely vary for each webhook payload and depend on how your system handles it. We usually do not recommend this method because, if not implemented carefully, it can easily introduce subtle bugs. For example:

    • If you are listening to the order.created event, you might check whether the incoming order_id is present in your database (DB), to determine if this payload has already been handled by your system.

    • On the other hand, if you are listening to the order.updated event, you may want to compare the incoming updated_at timestamp with the external_updated_at timestamp in your orders DB to determine whether this particular event has already been handled by your system.

  • Easy to implement (but not completely accurate): All webhook requests sent by the Fynd Platform include an x-fp-event-id header, which is unique for each request and it is preserved across retries. This header can be used to implement a straightforward (and centralized/common) logic to check if you have already handled a webhook request, or not. Our recommendation would be to implement this as HTTP middleware in your technology stack:

    • Maintain a cache (say in Redis, or even in your DB) of all the x-fp-event-ids that you have processed.

    • Before processing a webhook request, check if the incoming x-fp-event-id is present in the cache.

    • If it is present, emit a 202 Accepted HTTP response to indicate that the webhook was accepted, but not immediately acted upon.

    • If it is not present, process the webhook, add the x-fp-event-id to the cache, and emit a 200 OK HTTP response. Be careful to make an entry in this cache only after a webhook event is successfully processed and a 200 OK response is sent back, not before. In most HTTP-based middleware this is achieved by implementing an after_filter (or after_hook).

    • For the cache, please use a TTL of 50 hours, because currently, a webhook request can be retried up to approx 49 hours only (explained in the next section). Remember to delete items from this cache after 50 hours, especially if you are maintaining it in the DB, otherwise you may end-up with a constantly growing dataset.

      <CodeBlock language="javascript" code={`async function handleIdempotency(req, res) { // Extract the unique event identifier from the request headers const eventId = req.headers['x-event-id']; try { // Check if the event ID has already been processed const isProcessed = await checkIfProcessed(eventId);

          if (isProcessed) {
              // If the event has already been processed, return 202 Accepted
              return res.status(202).send('Event already processed');
          }
      
          // Process the webhook here
          // Example: console.log('Processing webhook:', req.body);
      
          // After successful processing, mark the event as processed
          await markAsProcessed(eventId);
      
          // Send 200 OK after successful processing
          res.status(200).send('Webhook processed successfully');
      } catch (error) {
          console.error('Error handling webhook:', error);
          res.status(500).send('Internal Server Error');
      }
      

      }`}>

Retries

  • Each event is retried a maximum of 10 times using an exponential-backoff algorithm. The last (i.e., tenth) retry occurs approximately 49 hours after the original attempt, after which that particular webhook request is marked as permanently failed and no longer retried.

  • Webhooks are always sent with the most recent data for the given resource; however, in rare circumstances, you might experience delays in receiving webhooks. We send a header with x-fp-attempt, which can be used to identify delays. We also send a created_timestamp in the payload that can be used to verify if the event was received out of order.

  • Upon failure (of any kind), webhooks will be retried in the following manner:

3. Handle payloads efficiently

  • Parsing and Processing: Ensure your webhook endpoint is capable of parsing JSON payloads quickly. This involves using efficient libraries and methods to deserialize the JSON data and process it. Keeping the processing lightweight helps avoid timeouts and maintain quick response times. Be prepared to handle large payloads (up to 5 MB in size).

  • Acknowledgment: After successfully processing a webhook event, your endpoint should respond with a 2XX status code within a time frame of 20 seconds, or the webhook request will be marked as a failure (and will be retried). A 2XX response indicates that the event has been received and processed correctly, preventing unnecessary retries.

  • Lightweight Endpoint: Design your webhook endpoint to be lightweight and responsive. Avoid long-running processes and offload heavy tasks to background jobs or asynchronous processing systems. This ensures your endpoint can respond quickly to incoming webhooks, reducing the risk of timeouts.

  • Appropriate Response Codes: Return appropriate HTTP status codes based on the result of processing the webhook. Use 2XX codes for successful processing and 5XX codes for server errors.

4. Additional Tips

  • Logging: Maintain detailed logs of all webhook events received. This helps with debugging issues and provides an audit trail for monitoring and security purposes.