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

# Receiving Event Updates

> Subscribe to webhook events and verify their signatures

Webhooks let you receive real-time notifications when events occur in Cula, such as when
a new sink is verified. The implementation follows the
[Standard Webhooks](https://www.standardwebhooks.com/) specification, using signatures
for secure verification.

## Setting Up Your Endpoint

Before creating a webhook, prepare an HTTPS endpoint on your server that can:

1. **Accept POST requests** with a JSON payload.
2. **Verify the signature** using your webhook secret.
3. **Respond with a 2xx status code** within 10 seconds to acknowledge receipt.

Example endpoint structure:

```js theme={null}
app.post('/webhooks/cula', (req, res) => {
  const signature = req.headers['webhook-signature'];
  const id = req.headers['webhook-id'];
  const timestamp = req.headers['webhook-timestamp'];
  const body = req.body;

  // Verify signature using the webhook secret
  if (!verifySignature(signature, id, timestamp, body)) {
    return res.status(401).send('Invalid signature');
  }

  // Process event
  console.log('Event received:', body.type, body.data);

  res.status(200).send('Event received');
});
```

## Creating a Webhook

Create a webhook by specifying your endpoint URL and the events you want to listen for:

```bash theme={null}
curl -X POST https://api.demo.cula.earth/tracking/v1/webhooks \
  -H "Authorization: Bearer your_access_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-domain.com/webhooks/cula",
    "events": ["sink.verified"],
    "description": "Production webhook for sink updates"
  }'
```

Response:

```json theme={null}
{
  "id": "wbh_01ktgcztz8cz5evcmgah1d1qcb",
  "url": "https://your-domain.com/webhooks/cula",
  "events": ["sink.verified"],
  "description": "Production webhook for sink updates",
  "secret": "whsec_...",
  "created_at": "2025-10-10T21:03:58Z",
  "updated_at": "2025-10-10T21:03:58Z"
}
```

<Warning>
  Save the `secret` (prefixed with `whsec_`) — you need it to verify webhook
  signatures. It is only returned when the webhook is created.
</Warning>

## Available Events

* `sink.verified` — triggered when a sink is verified.

## Webhook Headers

Every webhook request includes three standard headers:

| Header              | Description                                         | Example                          |
| ------------------- | --------------------------------------------------- | -------------------------------- |
| `webhook-id`        | Unique identifier for this message                  | `evt_01kmjgkf85kffncbydcxar5nvs` |
| `webhook-timestamp` | Unix timestamp (seconds since epoch) of the attempt | `1674087231`                     |
| `webhook-signature` | Signature in Standard Webhooks format               | `v1,hnO3f9T8Y...`                |

## Event Payload

When an event occurs, Cula sends a POST request to your endpoint:

```json theme={null}
{
  "type": "sink.created",
  "timestamp": "2025-10-10T21:03:58.000Z",
  "data": {
    "sink_id": "snk_01kpb4n7arexs9cjf0ffmdtjry"
  }
}
```

## Verifying Signatures

Webhook signatures must be verified to ensure authenticity. The verification process
follows the Standard Webhooks specification.

<Warning>
  Security considerations:

  * Verify the `webhook-timestamp` is within an acceptable tolerance (for example, 5
    minutes) to prevent replay attacks.
  * Use the `webhook-id` as an idempotency key to prevent processing the same event
    multiple times.
  * Store processed webhook IDs temporarily (for example, in Redis for 24 hours) to
    detect duplicates.
</Warning>

For implementation, use the official
[Standard Webhooks libraries](https://github.com/standard-webhooks/standard-webhooks),
available for multiple languages, which handle signature verification automatically.
