Webhooks Overview
Webhooks let you receive real-time HTTP notifications when events happen on your Sotion site, such as members signing up, signing in, or joining an access group. Instead of polling the API, you register a URL and Sotion pushes events to you as they occur.
Setting up a webhook
Webhooks live on the Integrations page of your site dashboard, under Advanced in the site's sidebar. Only Owners of your team can add or change them, on the Pro and Scale plans and during the free trial. On a lower plan the webhooks stay saved but nothing is sent.
On the Integrations page, click Add Webhook.
Enter a Name and the URL of your endpoint.
Under Events, tick the events to send.
Leave Signing Secret empty to have one generated, or enter your own of at least 16 characters.
Click Create Webhook, then copy the signing secret into your endpoint, to verify signatures.
A site can have 10 webhooks. The URL has to follow these rules:
It starts with
https://and holds no username or password.Its host is public: not
localhost, a private network address or a name that resolves to one. We check the host's DNS again before every delivery.It answers directly. We don't follow redirects, so an endpoint that redirects, for example to a version with or without
www, receives nothing.
Managing your webhooks
Each webhook's row on the Integrations page has a switch and a menu with the other actions.
The switch turns the webhook off and on. Events that happen while it is off are never sent, not even after you turn it back on.
Edit: change the name, the URL or the events.
View Secret: shows the signing secret. Set Custom there replaces it with one you enter.
Regenerate Secret: replaces the secret with a new one. Messages are signed with the new secret from then on, so update your endpoint's copy.
Delete: no more messages go to the webhook's URL.
You can also create webhooks with the API (POST /api/v1/webhooks), as automation tools do. The API returns the generated secret only in that response; its other requests show just the first characters. Those webhooks appear on the Integrations page too, where an Owner can view their secret.
Events
Event | Description |
|---|---|
| A member was added on the Members page or with the API's create-member request or its bulk create, signed up on your login page, or bought access through Stripe with an email that isn't a member yet |
| A member's details were changed on the Members page or through the API, or a Stripe purchase or cancellation changed a current member's paid status |
| A member signed in with an emailed link or code |
| A member was deleted on the Members page or through the API |
| A new access group was created |
| An access group's name or description was changed |
| An access group was deleted |
| A member was added to an access group |
| A member was removed from an access group |
When a new member joins with access groups, the groups come in member.created, not as separate access-group.member.added events. Event Payloads has each event's fields and exactly when we send it.
Payload format
Every webhook delivery sends a JSON payload wrapped in a standard envelope:
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "member.created",
"timestamp": "2026-03-28T12:00:00.000Z",
"version": "1",
"siteId": "site-uuid-here",
"data": {
...
}
}Field | Type | Description |
|---|---|---|
| string | Unique event ID (UUIDv4). Use this as an idempotency key to avoid processing the same event twice. |
| string | The event type, e.g. |
| string | ISO-8601 timestamp of when the event occurred |
| string | Envelope schema version. Currently |
| string | The ID of the site that generated the event |
| object | Event-specific payload (see Event Payloads) |
HTTP headers
Every webhook delivery is a POST request with the following headers:
Header | Description |
|---|---|
|
|
|
|
| The event type, e.g. |
| Unique ID for this event's delivery to this webhook. Retries of it keep the same ID. |
| The event ID (same as |
|
|
Your endpoint has to answer within 10 seconds with a 2xx status. Retry behavior explains what happens when it doesn't.