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

# Receive and verify Tekma webhooks

> Subscribe to capture-ready events, verify HMAC signatures, and handle Tekma webhook retries safely.

Webhooks notify your service when a capture becomes ready. Workspace owners configure endpoints under **Settings → Webhooks**.

## Create an endpoint

Enter a public HTTPS destination. Store the signing secret shown when the endpoint is created; it is shown once. Use **Send test** to confirm your receiver can accept a delivery.

The destination must not contain credentials or resolve to a private network. Redirects are not followed, so enter the final HTTPS URL directly.

## Verify every request

Tekma sends these headers:

| Header                    | Meaning                                               |
| ------------------------- | ----------------------------------------------------- |
| `X-Capture-Delivery`      | Delivery identifier for deduplication                 |
| `X-Capture-Event`         | Event name, including `capture.ready`                 |
| `X-Capture-Timestamp`     | Unix timestamp in milliseconds                        |
| `X-Capture-Signature-256` | `v1=` followed by a hexadecimal HMAC-SHA256 signature |

The signed message is the timestamp, a period, and the exact raw request body: `<timestamp>.<raw body>`. Verify before parsing or processing the payload. Do not reserialize JSON before checking the signature.

```javascript theme={null}
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyWebhook(rawBody, headers, secret, now = Date.now()) {
  const timestamp = headers.get('x-capture-timestamp');
  const signature = headers.get('x-capture-signature-256');
  if (!timestamp || !/^\d+$/.test(timestamp)) return false;
  if (Math.abs(now - Number(timestamp)) > 5 * 60 * 1000) return false;
  if (!signature || !/^v1=[a-f0-9]{64}$/.test(signature)) return false;
  const expected = createHmac('sha256', secret)
    .update(timestamp + '.')
    .update(rawBody)
    .digest();
  const received = Buffer.from(signature.slice(3), 'hex');
  return received.length === expected.length &&
    timingSafeEqual(received, expected);
}
```

Pass a `Buffer` containing the unmodified body and a Headers-compatible object. Load the signing secret from your receiver's secret storage, not source code.

## Handle retries

Deliveries time out after five seconds. Acknowledge accepted events promptly and move longer work into your own background queue. Persist the delivery identifier so repeated attempts do not create duplicate work.

Failed deliveries are retried with exponential backoff. After eight attempts, automatic retries stop. Use **Retry** in settings after fixing the receiver. **Send test** and **Retry** use the same signed delivery mechanism.

Deactivating an endpoint stops pending deliveries from being sent. Monitor receiver errors and the delivery results in Tekma when troubleshooting.
