# Rotate the webhook signing secret

Canonical page: https://docs.ovok.com/signals/standalone/api/clients/rotate-the-webhook-signing-secret

{/* Generated from the API Explorer document by scripts/generate-signals-api-pages.mjs. Edit ovok-core, not this page. */}


# Rotate the webhook signing secret [#rotate-the-webhook-signing-secret]

| Method | Path |
| --- | --- |
| `POST` | `/v1/signals/api/subscriber/{id}/webhook/rotate-secret` |

<Availability route="POST /v1/signals/api/subscriber/{id}/webhook/rotate-secret" />

Mints a new Standard Webhooks signing secret (`whsec_` and 32 random bytes) and returns it this once. Every delivery carries `webhook-id` and `webhook-timestamp`; once the subscriber has a secret it also carries `webhook-signature`, so a receiver verifies with the Standard Webhooks library. The secret it replaces keeps signing until `previousSecretExpiresAt` (24 h), so `webhook-signature` holds both and the receiver switches with no gap. Each rotation keeps only the secret it replaces, so rotate again only once the receiver uses the new one. The first call mints the subscriber's first secret. A MANAGER rotates any subscriber of its tenant; a SUBSCRIBER only its own.

### Through ovok [#through-ovok]

- **Who can call it:** Manager apps, and users whose access policy grants the capabilities.
- **Capabilities, all required:** `signals_webhooks:update`. Project admins have every capability; client applications get no admin bypass.
- It can reach any patient of your project without naming one, so it is for callers that reach every patient: project admins, manager or submitter apps, and anyone whose Patient access has no criteria.

## Request [#request]

### Path parameters [#path-parameters]

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes | The subscriber's Signals id or its `clientId`. |

## Responses [#responses]

| Status | Meaning |
| --- | --- |
| `200` | The new secret; it cannot be read back later. |
| `400` | A path value holds a character ovok does not send to Signals, such as a raw `:` or `+`. Percent-encode it. The query carries a raw `#`, or more than 200 parameters. |
| `401` | Your ovok access token, or your client id and secret, are missing or invalid. |
| `403` | ovok refused the call: you lack a capability this route needs, or your session has no project, or your access covers only some patients. From Signals: Authenticated, but the client's role does not permit this, or it is not attached to the patient. Or: A SUBSCRIBER named another subscriber. |
| `404` | No such subscriber in this tenant. |
| `409` | Your project has no Signals tenant of its own (`SIGNALS_TENANT_NOT_OWN`), or it is moving to another one. |
| `415` | The body is not JSON. |
| `429` | Too many requests. Retry after the seconds in `Retry-After`. |
| `500` | ovok hit an unexpected fault, such as your project having no Signals submitter. |
| `502` | Signals answered with something ovok couldn't use, or refused ovok's own credential. |
| `503` | Signals is unavailable. Retry after the seconds in `Retry-After`. |
| `504` | Signals did not answer in time. |

## Example [#example]

```bash
curl --request POST 'https://api.sandbox.ovok.com/v1/signals/api/subscriber/:id/webhook/rotate-secret' \
  --user "${OVOK_CLIENT_ID}:${OVOK_CLIENT_SECRET}" \
  --header 'Content-Type: application/json' \
  --data @body.json
```
