Rotate the signing secret
BuildingIn development for the v1 API. The contract is set; the route is not served yet.
Mints a new secret and answers it once. The previous secret keeps signing for expires_previous_in (24 hours by default, 7 days at most), so every delivery carries two v1 signatures meanwhile and you can switch without missing an event; 0s retires it at once. Never more than two secrets sign: a second rotation inside the overlap retires the oldest. At most 5 rotations per hour per subscription. No Idempotency-Key: every call rotates.
Needs the webhooks:write scope.
oauth2 webhooks:writeAuthorizationBearer <token>OAuth 2.0 client credentials. Exchange your client_id and client_secret at /oauth/token of the environment for a bearer token valid for one hour. The playground of every operation asks for your own client and keeps it in your browser tab only.
Scope: webhooks:write
id*stringThe subscription id.
^whk_[0-7][0-9a-hjkmnp-tv-z]{25}$application/json- body
expires_previous_in?stringHow long the previous secret keeps signing. Both signatures are sent meanwhile; 0s retires it at once. A duration such as 24h, 0s or 168h; at most 168h.
"24h"The subscription with its new secret. Store it: it is never shown again.
application/json- response
id*string^whk_[0-7][0-9a-hjkmnp-tv-z]{25}$url*stringuridescription*stringevent_types*array<string>merchant_ids*array<>status*stringactive delivers; paused you set it and deliveries wait; disabled heru set it (see disabled_reason) and deliveries wait until you send status: active.
"active""paused""disabled"disabled_reason*|nulldisabled_at*|nullheaders*array<>secret?stringOnly in the answer of POST /webhooks and POST /webhooks/{id}/secret. Store it: it is never shown again.
^whsec_[A-Za-z0-9_-]{43}$secret_last4*stringsecret_rotating_until*|nullconsecutive_failures*integerFailed deliveries in a row. A 2xx resets it to zero.
failing_since*|nullenvironment*string"sandbox""production"created_at*stringdate-timeupdated_at*stringdate-timedeliveries*Where the delivery log of this subscription is.
curl -X POST 'https://api.dev.b2b.heru.app/v1/webhooks/whk_01m53g5zw414zt6vg08fqbacgm/secret' \ -H 'Content-Type: application/json' \ -d '{ "expires_previous_in": "24h"}'{ "id": "whk_01m53g5zw414zt6vg08fqbacgm", "url": "https://partner.example.com/heru/webhooks", "description": "POS production", "event_types": [ "invoice.stamped", "charge.invoiced" ], "merchant_ids": [ "mer_01m4ra8wsyfh3s0tr4nrq3y96j" ], "status": "active", "disabled_reason": null, "disabled_at": null, "headers": [ { "name": "X-Partner-Token", "value": "****abcd" } ], "secret": "whsec_9vPq2zL0rXk4T8nWbYc1mAe6HdJfSg3uKoRiQtVxZ7w", "secret_last4": "xZ7w", "secret_rotating_until": "2026-10-27T15:04:41.000Z", "consecutive_failures": 0, "failing_since": null, "environment": "production", "created_at": "2026-10-25T12:00:00.000Z", "updated_at": "2026-10-26T15:04:41.000Z", "deliveries": { "path": "/v1/webhooks/whk_01m53g5zw414zt6vg08fqbacgm/deliveries" }}Create a webhook subscriptionPOST
Registers a URL to receive the events listed, signed with a secret of its own. The answer carries `secret` once: store it, it is never shown again. Retrying with the same `Idempotency-Key` and body returns the same subscription, `secret` included. A company can hold up to 10 subscriptions. See the [Webhooks guide](/guides/webhooks) for signature verification, idempotency and retries. Needs the `webhooks:write` scope.
Send a test event nowPOST
Posts a signed `webhook.test` event (`data: {webhook_id, message}`) to the URL right away, with the secrets and extra headers in force, and answers what the endpoint replied. One attempt, no retries; it works on a `paused` or `disabled` subscription and does not count towards `consecutive_failures`. The delivery shows in the log like any other. At most 10 per minute per subscription. Needs the `webhooks:write` scope.