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

# Webhooks

> Receive real-time events when entity data changes

Pointset pushes events to your webhook URL whenever entities change. Configure your endpoint via the [webhook API](/api-reference/webhook/update), and Pointset will POST a signed JSON payload for each event.

## Events

| Event               | When it fires                                    |
| ------------------- | ------------------------------------------------ |
| `entity.discovered` | A new entity matching your subscription is found |
| `entity.updated`    | One or more of your subscribed fields changed    |
| `entity.removed`    | An entity no longer appears in source data       |

Each delivery contains up to 25 entities. Large batches are split into multiple requests.

## Verifying signatures

Every request includes an `X-Pointset-Signature` header:

```
X-Pointset-Signature: sha256=<hex>
```

The signature is HMAC-SHA256 of the raw request body, keyed with your webhook secret. Verify it before processing:

```typescript theme={null}
async function verifySignature(secret: string, body: string, header: string): Promise<boolean> {
  const encoder = new TextEncoder()
  const key = await crypto.subtle.importKey(
    'raw', encoder.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false, ['verify']
  )
  const expected = header.replace('sha256=', '')
  const sig = await crypto.subtle.sign('HMAC', key, encoder.encode(body))
  const actual = Array.from(new Uint8Array(sig))
    .map(b => b.toString(16).padStart(2, '0')).join('')
  return actual === expected
}
```

Your secret is returned when you first configure the webhook, or when you rotate it. Store it securely — it is not shown again.

## Retries

If your endpoint returns a non-2xx response (or times out), Pointset retries with exponential backoff:

| Attempt | Delay                            |
| ------- | -------------------------------- |
| 1       | 30s                              |
| 2       | 60s                              |
| 3       | 120s                             |
| …       | doubles each time, capped at 24h |

After 10 failed attempts the delivery is marked failed and not retried. Return a 2xx as quickly as possible — process events asynchronously if needed.

## The `fields` object

Each entity in the payload includes only the fields your subscription requested, not the full entity record. If you need additional fields, update your subscription.
