7 endpoints.
| Method | Path | Summary |
|---|---|---|
GET | /api/communities/{communityId}/webhooks | List this community's webhook endpoints |
POST | /api/communities/{communityId}/webhooks | Create a webhook endpoint |
DELETE | /api/communities/{communityId}/webhooks/{webhookId} | Delete a webhook endpoint |
PATCH | /api/communities/{communityId}/webhooks/{webhookId} | Update a webhook endpoint |
GET | /api/communities/{communityId}/webhooks/{webhookId}/deliveries | Delivery log for one endpoint |
POST | /api/communities/{communityId}/webhooks/{webhookId}/rotate-secret | Mint a new signing secret |
POST | /api/communities/{communityId}/webhooks/{webhookId}/test | Send a test delivery |
GET /api/communities/{communityId}/webhooksNever returns a signing secret. It does reveal every delivery target the community has configured, which is why it requires WEBHOOKS_MANAGE rather than plain membership.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | path | yes | string (uuid) | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | The community's endpoints | object |
403 | FEATURE_NOT_AVAILABLE, or the caller lacks WEBHOOKS_MANAGE | — |
POST /api/communities/{communityId}/webhooksThe response carries a plaintext secret exactly once. There is no route that reads it back — if it is lost, the only recovery is rotate-secret, which invalidates the oldest secret.
The URL is validated against SSRF at create time: HTTPS on port 443 only, no redirects, and the resolved IP is re-checked at socket-connect time so a DNS rebind cannot slip past.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | path | yes | string (uuid) | — |
Request body (required) — application/json
| Field | Type | Required | Description |
|---|---|---|---|
url | string (uri) | yes | — |
events | string[] | yes | — |
description | string | no | — |
Responses
| Status | Description | Body |
|---|---|---|
201 | Created. data.secret is present here and never again. | object |
400 | Invalid URL (non-HTTPS, private/loopback target, redirecting) or unknown event name | — |
429 | Rate limited — 10 burst, ~1 per 10s sustained | — |
DELETE /api/communities/{communityId}/webhooks/{webhookId}Permanent. The delivery log cascades with it, so export anything you need first. To stop deliveries temporarily, PATCH isActive: false.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | path | yes | string (uuid) | — |
webhookId | path | yes | string (uuid) | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | Deleted | — |
404 | No such endpoint in this community | — |
PATCH /api/communities/{communityId}/webhooks/{webhookId}Partial update. Setting isActive: false pauses deliveries without losing the endpoint or its secrets — prefer it over delete when troubleshooting. Re-enabling an endpoint the platform auto-disabled also clears disabledAt and the failure counter.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | path | yes | string (uuid) | — |
webhookId | path | yes | string (uuid) | — |
Request body — application/json
| Field | Type | Required | Description |
|---|---|---|---|
url | string (uri) | no | — |
events | string[] | no | — |
description | string | no | — |
isActive | boolean | no | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | The updated endpoint | object |
404 | No such endpoint in this community | — |
GET /api/communities/{communityId}/webhooks/{webhookId}/deliveriesEvery delivery ATTEMPT, newest first. A retried event appears several times under one messageId, with attempt counting up — that is the fastest way to tell "we never called you" apart from "we called you and your server answered 500".
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | path | yes | string (uuid) | — |
webhookId | path | yes | string (uuid) | — |
limit | query | no | integer | — |
offset | query | no | integer | — |
status | query | no | enum: PENDING, SUCCESS, FAILED | Filter to one outcome. FAILED is the useful one when debugging. |
Responses
| Status | Description | Body |
|---|---|---|
200 | A page of delivery attempts | object |
POST /api/communities/{communityId}/webhooks/{webhookId}/rotate-secretReturns a new plaintext secret exactly once. The previous secret stays valid for an overlap window so a running integration is not cut off mid-deploy: deliveries are signed with EVERY live secret, and your verifier accepts the request if any signature matches. Deploy the new secret during that window. Rate limited harder than create (5 burst, ~1 per 20s): each rotation retires the oldest secret, so a caller looping this would silently break its own live integration.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | path | yes | string (uuid) | — |
webhookId | path | yes | string (uuid) | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | The new secret. Not retrievable again. | object |
429 | Rate limited | — |
POST /api/communities/{communityId}/webhooks/{webhookId}/testDelivers a synthetic webhook.test event to this endpoint so you can confirm reachability and signature verification before relying on it.
webhook.test is deliberately NOT in the subscribable catalog — it only ever fires when a human presses this. For the same reason the send ignores the endpoint's events list and its isActive flag: the two moments you most need this button are right after creating an endpoint (subscribed to nothing yet) and after the platform auto-disabled one.
The request is signed with the real secrets and recorded in the real delivery log — a test that took a different code path would prove nothing about the path that matters.
A failure is returned as an ERROR status, never as a 200 with success: false. You pressed this to find out whether your server answers.
Auth: Bearer JWT required.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
communityId | path | yes | string (uuid) | — |
webhookId | path | yes | string (uuid) | — |
Responses
| Status | Description | Body |
|---|---|---|
200 | Your endpoint accepted the test delivery | object |
404 | No such endpoint in this community | — |
429 | Rate limited — 5 burst | — |
500 | The delivery was attempted and failed. Read the delivery log for the response your server gave. | — |