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

# Webhooks

> Configure real-time notifications for blockchain events in Hub

## Why Use Webhooks?

| Approach     | Latency            | Complexity | Use Case                       |
| ------------ | ------------------ | ---------- | ------------------------------ |
| **Polling**  | Seconds to minutes | Simple     | Low-volume, non-critical       |
| **Webhooks** | Sub-second         | Moderate   | Real-time updates, high-volume |

## Configure Webhooks

Configure in [Hub](https://hub.immutable.com): **Webhooks** → **Add Webhook**

**Endpoint URL:** e.g., `https://api.yourgame.com/webhooks/immutable`

**Events:** Mints, transfers, orders, trades

## Webhook Payload

```json theme={null}
{
  "event_name": "imtbl_zkevm_mint_request_updated",
  "event_id": "evt_123abc",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "contract_address": "0x...",
    "token_id": "123",
    "status": "succeeded"
  }
}
```

## Verify Webhook Signatures

```typescript theme={null}
import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
app.post('/webhooks/immutable', (req, res) => {
  const signature = req.headers['x-immutable-signature'];
  const isValid = verifyWebhookSignature(
    JSON.stringify(req.body),
    signature,
    process.env.WEBHOOK_SECRET
  );
  
  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process the webhook
  handleWebhookEvent(req.body);
  res.status(200).send('OK');
});
```

## Retry Policy

Exponential backoff on errors:

| Attempt | Delay      |
| ------- | ---------- |
| 1       | Immediate  |
| 2       | 1 minute   |
| 3       | 5 minutes  |
| 4       | 30 minutes |
| 5       | 2 hours    |

After 5 failed attempts, view and retry in Hub.

## Best Practices

<AccordionGroup>
  <Accordion title="Respond quickly">
    Return a 200 response immediately, then process the event asynchronously. Webhook requests timeout after 30 seconds.
  </Accordion>

  <Accordion title="Handle duplicates">
    Use the `event_id` to deduplicate events. The same event may be delivered more than once.
  </Accordion>

  <Accordion title="Secure your endpoint">
    Always verify the webhook signature. Use HTTPS for your endpoint.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Indexer API" icon="database" href="/docs/products/indexer/overview">
    Query blockchain data directly
  </Card>

  <Card title="Minting Events" icon="coins" href="/docs/products/asset-contracts/minting-api">
    Handle minting webhooks
  </Card>
</CardGroup>
