API reference
Webhooks API
Reference for creating, listing, retrieving, updating, deleting and rotating the signing secret of webhooks.
The webhooks API manages the webhooks of the project that owns your API key. Every endpoint needs a full_access key. For the concepts, see Webhooks overview, Event types and Verify signatures.
The webhook object
{
"object": "webhook",
"id": "jw6k9d3h2s5f8g1j4l7z0x2c",
"created_at": "2026-11-14T10:00:00.000Z",
"status": "enabled",
"endpoint": "https://yourapp.com/webhooks/sooner",
"events": ["email.delivered", "email.bounced"],
"signing_secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"
}status is enabled or disabled. signing_secret is included when you retrieve a single webhook, and left out of list items.
Create a webhook
| Field | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | A public https URL. Private and local addresses are rejected. |
events | string[] | Yes | At least one event type, or "*" for all. Unknown names are ignored. |
curl -X POST https://api.sooner.dev/webhooks \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "https://yourapp.com/webhooks/sooner",
"events": ["email.delivered", "email.bounced"]
}'{
"object": "webhook",
"id": "jw6k9d3h2s5f8g1j4l7z0x2c",
"signing_secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"
}Notable errors: validation_error for a URL that is not https, a private address, no supported event names, or the plan's webhook limit (5 on Free, 20 on Pro, 50 on Scale).
List webhooks
Returns the project's webhooks, newest first, without signing secrets. Accepts limit and after. See Pagination.
curl https://api.sooner.dev/webhooks \
-H "Authorization: Bearer $SOONER_API_KEY"{
"object": "list",
"data": [
{
"object": "webhook",
"id": "jw6k9d3h2s5f8g1j4l7z0x2c",
"created_at": "2026-11-14T10:00:00.000Z",
"status": "enabled",
"endpoint": "https://yourapp.com/webhooks/sooner",
"events": ["email.delivered", "email.bounced"]
}
],
"has_more": false
}Retrieve a webhook
Returns one webhook, including its signing_secret. Notable errors: not_found.
Update a webhook
Changes only the fields you send.
| Field | Type | Required | Description |
|---|---|---|---|
endpoint | string | No | A new public https URL. |
events | string[] | No | A new, non-empty list of event types. Unknown names are dropped. |
status | string | No | enabled or disabled. A disabled webhook receives nothing. |
curl -X PATCH https://api.sooner.dev/webhooks/jw6k9d3h2s5f8g1j4l7z0x2c \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "disabled" }'{ "object": "webhook", "id": "jw6k9d3h2s5f8g1j4l7z0x2c" }Notable errors: validation_error for an invalid endpoint, not_found.
Delete a webhook
curl -X DELETE https://api.sooner.dev/webhooks/jw6k9d3h2s5f8g1j4l7z0x2c \
-H "Authorization: Bearer $SOONER_API_KEY"{ "object": "webhook", "id": "jw6k9d3h2s5f8g1j4l7z0x2c", "deleted": true }Rotate the signing secret
Generates a new secret and returns it. The old secret stops signing right away. See Verify signatures for how to switch without dropping events.
curl -X POST https://api.sooner.dev/webhooks/jw6k9d3h2s5f8g1j4l7z0x2c/signing-secret/rotate \
-H "Authorization: Bearer $SOONER_API_KEY"{
"object": "webhook",
"id": "jw6k9d3h2s5f8g1j4l7z0x2c",
"signing_secret": "whsec_t9Qm2Xv7LpRk4NwYb8Hc1ZaE5JdGfU0s"
}