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

# Webhooks

> How Onstacks delivers and signs events, and how to verify them.

Webhooks are workspace-scoped and environment-scoped. Manage them under **Developer** in the dashboard or with the webhook endpoints in the API reference. Each product documents its own event names; the delivery and signing mechanics on this page are the same for all of them.

## Delivery

Each delivery is an HTTPS `POST` with a JSON body:

```json theme={"system"}
{
  "id": "evt_...",
  "type": "webhook.test",
  "created_at": "2026-09-12T14:00:00Z",
  "data": {}
}
```

| Header | Value |
| - | - |
| `X-Onstacks-Webhook-ID` | Event id. Use it to de-duplicate. |
| `X-Onstacks-Webhook-Type` | Event type, same as `type` in the body. |
| `X-Onstacks-Webhook-Timestamp` | Unix seconds when the delivery was signed. |
| `X-Onstacks-Webhook-Signature` | `v1=` followed by a hex HMAC-SHA256. |
| `User-Agent` | `Onstacks-Webhooks/1.0` |

Respond with any `2xx` within ten seconds. Failed deliveries are retried and can be resent from the dashboard or with the resend endpoint.

## Verify the signature

Compute HMAC-SHA256 with your webhook secret over the string `timestamp + "." + raw_body` and compare it to the signature in constant time. Reject deliveries whose timestamp is older than five minutes.

```javascript theme={"system"}
import crypto from "node:crypto";

export function verify(secret, headers, rawBody) {
  const ts = headers["x-onstacks-webhook-timestamp"];
  const expected = "v1=" + crypto
    .createHmac("sha256", secret)
    .update(`${ts}.${rawBody}`)
    .digest("hex");
  const given = headers["x-onstacks-webhook-signature"];
  return given.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
```

## Secrets

The signing secret is returned once when the webhook is created and again when rotated. Rotate from the dashboard or with the rotate endpoint; disable and enable without losing the configuration.

## Testing

The **Test** action, or `POST /v1/webhooks/{webhookId}/test`, sends a `webhook.test` event so you can verify your endpoint and signature handling before real events flow.

## Event catalogues

* [Ramp events](/ramps/reference/webhook-events)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.