---
title: "Manage subscriptions"
description: "Create, scope, pause, inspect, and delete webhook subscriptions through the Server API; test and manually retry from the dashboard."
---

Use the Webhooks API when subscription setup must be repeatable across customer
provisioning, environments, or deployment pipelines. One-off integrations can
use the dashboard over the same underlying resources.

The stable Server API/SDK surface covers subscription CRUD and delivery-list
inspection. Sending a representative test and manually redelivering one stored
attempt are operator actions in the dashboard for this launch; they are not
published OpenAPI operations or server-SDK methods. Do not build an integration
against the dashboard's internal action routes.

## Authentication

Secret keys have organization authority within their webhook routing scope.
Dashboard reads allow signed-in members; writes require an admin. Event-scoped
manage tokens cannot access webhook configuration.

Dashboard members see every subscription in their organization. Secret keys
are narrower for webhook management:

- a live key cannot list, inspect, update, or delete a test-mode
  subscription, and a test key cannot manage a live subscription;
- an environment-tagged key can manage subscriptions only in that same webhook
  routing environment; and
- a key without an environment tag is broad across environments, but only
  within its live/test mode.

Out-of-scope subscription IDs answer `404` and reveal no delivery metadata.
This fence protects webhook routing configuration. Event `environment` remains
routing metadata—not an event authorization boundary.

Legacy subscriptions whose mode is `null` continue to receive both live and
test occurrences, but are dashboard-managed only. An admin can assign one a
concrete live/test mode before returning its management to a secret-key
integration.

| Method and path | Purpose |
|---|---|
| `GET /v1/webhooks` | List subscriptions and seven-day uptime |
| `POST /v1/webhooks` | Create; signing secret returned once |
| `PATCH /v1/webhooks/:id` | Update URL, events, disabled state, or scope |
| `POST /v1/webhooks/:id/rotate-secret` | Rotate signing secret; replacement returned once |
| `DELETE /v1/webhooks/:id` | Delete subscription |
| `GET /v1/webhooks/:id/deliveries` | Inspect delivery attempts |

## Create a subscription

<ApiEndpoint method="POST" path="/v1/webhooks" auth="Secret key or admin dashboard session" />

```bash
curl -sX POST "https://api.seatlayer.io/v1/webhooks" \
  -H "authorization: Bearer $SEATLAYER_SECRET_KEY" \
  -H "content-type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/seatlayer",
    "events": [
      "seat.booked",
      "seat.released",
      "event.soldout"
    ]
  }'
```

The URL must use HTTPS, fit within 2,048 characters, and `events` must be a
non-empty set of known names. An organization can keep up to 10 active
subscriptions and 25 subscriptions in total, including paused ones. Delete an
unused paused subscription to free a saved slot.

```json
{
  "sub": {
    "id": "sub_8a2f",
    "url": "https://example.com/webhooks/seatlayer",
    "events": ["seat.booked", "seat.released", "event.soldout"],
    "disabled": false,
    "lastStatus": null,
    "lastAt": null,
    "createdAt": 1761436800000,
    "mode": "live",
    "environment": "prod",
    "uptime7d": null
  },
  "secret": "whsec_1f8c"
}
```

<Aside type="caution" title="Store the secret now">
  `secret` is returned only at creation or rotation and is never included in
  list or patch responses. Rotation preserves subscription identity, scope,
  and delivery history while invalidating the previous secret for new sends.
</Aside>

## Scope delivery

Subscriptions can filter by `mode` and `environment`.

- A secret-key create inherits that key's mode and environment.
- A dashboard-session create defaults to live mode and accepts an optional
  environment.
- A dashboard admin, or a key without an environment tag, may use a `null`
  environment as a wildcard. A dashboard admin may also use `mode: null` for a
  cross-mode legacy subscription; no live/test secret key can manage it.

```json
{
  "url": "https://staging.example.com/webhooks/seatlayer",
  "events": ["seat.booked"],
  "mode": "test",
  "environment": "staging"
}
```

A secret-key create always derives scope from the key; supplied `mode` or
`environment` fields cannot override it. Secret keys cannot rescope a
subscription after creation. Identical echoed fields are accepted as no-ops;
changing either axis returns `403 webhook_scope_immutable`. A key that names an
out-of-scope subscription receives `404` before any resource metadata is
returned.

## Update or pause

<ApiEndpoint method="PATCH" path="/v1/webhooks/:id" auth="Secret key or admin dashboard session" />

Send only changed fields. `events` replaces the full set.

```json
{
  "events": [
    "seat.booked",
    "seat.released",
    "hold.created",
    "hold.expired"
  ],
  "disabled": true
}
```

Pause with `disabled: true` while repairing a receiver. Existing delivery
history remains available. Dashboard admins can send `mode: null` or
`environment: null` to restore a wildcard. Secret keys may update URL, events,
and disabled state only; they cannot change subscription scope.

## Rotate the signing secret

<ApiEndpoint method="POST" path="/v1/webhooks/:id/rotate-secret" auth="Secret key or admin dashboard session" />

Rotation returns `{ sub, secret }` with `Cache-Control: no-store`. The new
secret is shown once. Subscription ID, URL, event set, scope, and delivery
history are unchanged; new deliveries immediately use only the replacement.
Pause the endpoint first when the receiver deployment cannot update its secret
atomically.

## Send a test

In the dashboard, choose **Send test** on a subscription. SeatLayer sends a
signed `ping` and waits up to five seconds:

```json
{
  "status": 200,
  "ok": true,
  "event": "ping",
  "responseBody": null
}
```

An admin can choose a representative payload such as:

```json
{
  "event": "seat.booked"
}
```

Representative tests are available for seat booked/released/blocked, hold
created/expired, and event created/sold-out branches. Exercise
`hold.extended` using a test-mode event. Test requests carry `test: true`,
are delivered inline, and are not written to the normal delivery ledger.

## Inspect deliveries

<ApiEndpoint method="GET" path="/v1/webhooks/:id/deliveries" auth="Secret key or dashboard session" />

Query parameters:

| Parameter | Behavior |
|---|---|
| `limit` | Default 20; maximum 50 |
| `status` | `ok`, `failed`, or omit for both |
| `before` | Timestamp cursor from `nextBefore` |

Cursor pages can overlap at the timestamp boundary; de-duplicate by delivery
`id`. Each record includes status, attempt count, retry state, occurrence id,
stored payload, and—on failure—a truncated receiver response or transport error.

## Retry one delivery

In the dashboard delivery panel, choose **Retry**. This sends the stored payload
to that subscription only. It keeps the original `occurrenceId`, creates a new
delivery attempt and signature, and does not restart the automatic retry chain.
Manual retry is not a stable server-SDK operation in this release.

## Delete

<ApiEndpoint method="DELETE" path="/v1/webhooks/:id" auth="Secret key or admin dashboard session" />

Deletion removes the subscription. If temporary downtime is expected, prefer
`disabled: true` so configuration and history remain available.

Continue to [event payloads](/webhooks/events),
[delivery and retries](/webhooks/delivery-and-retries), and
[signature verification](/webhooks/signatures).