> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crossmint.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Best Practices

> Best practices for implementing reliable webhook handlers

Follow these best practices to ensure your webhook implementation is reliable, secure, and performant.

## Idempotency

Crossmint webhooks follow an at-least-once delivery guarantee. Duplicate deliveries can occur (for example, if a previous attempt didn't receive a 2xx response quickly enough). Implement idempotency by:

1. Using the webhook `id` field as a unique identifier
2. Storing processed webhook IDs in your database
3. Checking if a webhook has already been processed before taking action

> **Note:** The following code examples are pseudocode for illustration purposes.

```javascript theme={null}
async function handleWebhook(webhookId, data) {
  // Check if we've already processed this webhook
  const existing = await db.webhooks.findOne({ id: webhookId });
  if (existing) {
    console.log('Webhook already processed:', webhookId);
    return;
  }
  
  // Process the webhook
  await processWebhook(data);
  
  // Mark as processed
  await db.webhooks.create({ id: webhookId, processedAt: new Date() });
}
```

## Response Time

Your webhook endpoint must respond within 15 seconds, otherwise the webhook will be resent. For long-running operations:

<Important>
  If your endpoint doesn't return a 2xx status code within 15 seconds, the delivery attempt is marked as failed and Crossmint will automatically retry with exponential backoff. This can result in duplicate deliveries (at-least-once semantics). After repeated failures, the message is marked as undeliverable and you can manually trigger redelivery from the Console. See [Add an Endpoint](/introduction/platform/webhooks/add-endpoint) for the full retry schedule.
</Important>

1. Immediately acknowledge the webhook with a 200 response
2. Queue the processing work for asynchronous execution
3. Process the webhook data in a background job

> **Note:** The following code examples are pseudocode for illustration purposes.

```javascript theme={null}
app.post('/webhooks/your-endpoint', async (req, res) => {
  // Verify signature first
  const payload = verifyWebhook(req);
  
  // Immediately acknowledge receipt
  res.status(200).json({ received: true });
  
  // Queue for background processing
  await jobQueue.add('process-webhook', {
    webhookId: payload.id,
    type: payload.type,
    data: payload.data,
  });
});
```

## Error Handling

Implement proper error handling to ensure reliable webhook delivery:

* **Return 2xx within 15 seconds** after verifying the signature to acknowledge receipt
* **Return 400** for invalid signatures to reject the webhook
* **Return 5xx** for transient internal errors to trigger automatic retries

See [Verify Webhooks](/introduction/platform/webhooks/verify-webhooks) for more details on signature verification and error handling.

## Signature Verification

Always verify webhook signatures to ensure requests are legitimate and come from Crossmint. Never process webhooks without verifying their signatures first.

See [Verify Webhooks](/introduction/platform/webhooks/verify-webhooks) for detailed instructions on signature verification.

## Related Resources

* [Add an Endpoint](/introduction/platform/webhooks/add-endpoint) - Configure webhook endpoints
* [Verify Webhooks](/introduction/platform/webhooks/verify-webhooks) - Verify webhook signatures
* [Overview](/introduction/platform/webhooks/overview) - Learn about webhooks
