Pular para o conteúdo

Manage webhook endpoints

All endpoint management routes require an authenticated full administrator and use application/vnd.api+json.

create or change URL → pending-verification → active ⇄ paused → deleted
  • New endpoints and changed URLs must pass verification before receiving production events.
  • An active endpoint can be paused manually.
  • Endpoints paused manually or for delivery health can be resumed if the current destination is still verified.
  • A destination blocked by the security policy cannot be resumed directly. Change it to a valid public HTTPS URL and verify the new destination.
  • Deletion is final. Undelivered work for that endpoint is suppressed and its secrets are cleared.

Events captured while an endpoint is pending or paused are not delivered when it later becomes active. Pausing, removing a subscription, changing a URL, or deleting an endpoint can suppress already-pending deliveries.

Method Path Purpose
GET /v1/webhook-endpoints List live endpoints.
GET /v1/webhook-endpoints/:id Read one endpoint and its current ETag.
POST /v1/webhook-endpoints Create an endpoint.
PATCH /v1/webhook-endpoints/:id Change its name, subscriptions, URL, or status.
DELETE /v1/webhook-endpoints/:id Delete an endpoint.
POST /v1/webhook-endpoint-verifications Queue destination verification.
POST /v1/webhook-endpoint-secret-rotations Rotate the signing secret.
POST /v1/webhook-test-deliveries Queue a one-attempt test.

Endpoint lists use page[number] and page[size]. The default page size is 25 and the maximum is 100.

Attribute Description
name Optional display name, at most 120 characters.
url HTTPS destination, at most 2,048 characters. Credentials and fragments are not allowed. DNS must resolve only to public addresses.
events Non-empty, unique array of supported event types.
status pending-verification, active, or paused. Deleted endpoints are not returned.
effective-health pending-verification, paused, healthy, degraded, or failing.
pause-reason manual, health, security-policy, or null.
configuration-version Optimistic-concurrency version used by If-Match and verification.
destination-version Increments when the URL changes.
verified-destination-version Version most recently verified, or null.
secret-generation Current signing-secret generation.
verified-at Time the current destination was verified, or null.
last-production-attempt-at Most recent production attempt time.
last-production-success-at Most recent production success time.
last-production-failure-at Most recent production failure time.
consecutive-production-failures Current consecutive failure count.
last-production-failure Diagnostic code and message, or null.
metrics Separate rolling metrics for 24h and 7d, including attempts, retries, latency, and terminal success.
created-at, updated-at Endpoint timestamps.

GET /v1/webhook-endpoints/:id and successful endpoint writes return an ETag such as:

ETag: "webhook-endpoint-4"

Every PATCH and DELETE must send the current value:

If-Match: "webhook-endpoint-4"

A stale version returns 409 Conflict; a missing or malformed header returns 428 Precondition Required. Fetch the endpoint again before deciding whether to retry.

name and events can be changed together. Removing an event type suppresses pending deliveries for that removed subscription.

Terminal window
curl --request PATCH 'https://api.celula.in/v1/webhook-endpoints/ENDPOINT_ID' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/vnd.api+json' \
--header 'If-Match: "webhook-endpoint-4"' \
--data '{
"data": {
"type": "webhook-endpoints",
"attributes": {
"name": "People synchronization",
"events": ["person.created", "person.updated", "person.merged"]
}
}
}'

A status transition must be the only attribute in the request:

{
"data": {
"type": "webhook-endpoints",
"attributes": { "status": "paused" }
}
}

Send the same shape with "status": "active" to resume an endpoint paused manually or for health. Both requests require the current If-Match value.

The API dispatches a URL reset based on the presence of attributes.url, not on whether its value changed. Any accepted PATCH that includes url—even the current URL or another value that normalizes to it—performs the complete destination reset described below. Omit url unless you intend to rotate the secret, suspend delivery, and verify the destination again. In particular, do not send a full stored endpoint representation when updating only name or events.

A PATCH containing url requires both If-Match and Idempotency-Key. It can include name and events in the same request.

Terminal window
curl --request PATCH 'https://api.celula.in/v1/webhook-endpoints/ENDPOINT_ID' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/vnd.api+json' \
--header 'If-Match: "webhook-endpoint-4"' \
--header 'Idempotency-Key: move-endpoint-to-v2' \
--data '{
"data": {
"type": "webhook-endpoints",
"attributes": {
"url": "https://integrations.example.com/v2/webhooks/celulain"
}
}
}'

The update:

  • moves the endpoint to pending-verification;
  • increments its configuration, destination, and secret generations;
  • suppresses undelivered requests for the old URL;
  • invalidates the old secret immediately;
  • returns the new secret once in data.meta.secret.

Store the new secret and verify the destination again. Exact retries using the same idempotency key and request return the same result for 24 hours. Reusing the key with different input returns 409 Conflict.

Read the endpoint’s current secret-generation, then submit it with a unique idempotency key:

Terminal window
curl --request POST 'https://api.celula.in/v1/webhook-endpoint-secret-rotations' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/vnd.api+json' \
--header 'Idempotency-Key: rotate-production-secret-2026-08' \
--data '{
"data": {
"type": "webhook-endpoint-secret-rotations",
"attributes": {
"secret-generation": 3
},
"relationships": {
"endpoint": {
"data": { "type": "webhook-endpoints", "id": "ENDPOINT_ID" }
}
}
}
}'

The 201 Created response returns the new generation and new secret in data.meta.secret. Store it before discarding the response.

For the next 48 hours, requests contain signatures from both the new and previous secret. Deploy the new secret to your receiver, accept either secret during the overlap, and remove the old secret after the overlap ends. Another rotation for the endpoint is rejected while an overlap is active.

Idempotent replay is available for 24 hours. A successful replay with the same request returns the same secret; a mismatched or expired replay never exposes a secret.

Action Per account Per endpoint Window
Verification 20 5 1 hour
Test delivery 60 10 1 hour
Manual redelivery 100 20 1 hour
Secret rotation 10 1 48 hours

Exceeding a limit returns 429 Too Many Requests. Outbound-triggering actions fail with 503 Service Unavailable if their action limiter is unavailable.