> The full uetr.ai documentation index is at https://uetr.ai/llms.txt, and every page under https://uetr.ai/docs/api is also Markdown at its address plus `.md`.

# Rotate a webhook signing secret

Replace a webhook endpoint's signing secret, for example after it was exposed. The new secret is returned once, here. For the next 24 hours every delivery carries two signatures, one with the new secret and one with the previous secret, so the receiver keeps accepting requests while it is updated; after that only the new secret signs. Rotating again within those 24 hours ends the oldest secret at once: only the secret in use at that moment keeps signing beside the new one. The address, events and status do not change. Only the account owner's API keys and connected apps can rotate a secret.

`POST https://uetr.ai/api/v1/webhooks/{id}/rotate-secret`

- MCP tool: `rotate_webhook_secret`
- Access: a key or connection with read and write access
- Only the account owner's keys and connections

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string (uuid) | Yes | The webhook endpoint's id. |

## Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `endpoint` | object | Yes |  |
| `endpoint.id` | string (uuid) | Yes |  |
| `endpoint.url` | string | Yes | The address's host and a masked path. The full address is never shown. |
| `endpoint.destination` | `json`, `slack`, `teams` | Yes | json: signed JSON. slack and teams: a readable message for a Slack or Microsoft Teams incoming webhook. |
| `endpoint.events` | array of `status_changed`, `final_state`, `checks_ended` | Yes |  |
| `endpoint.status` | `pending`, `active`, `paused` | Yes | pending: waiting for the account owner to confirm it on the website; until then it receives test events only. active: receiving events. paused: deliveries stopped after sustained failures; a test event that succeeds resumes it. |
| `endpoint.paused_at` | string or null | Yes |  |
| `endpoint.created_at` | string | Yes |  |
| `endpoint.created_by` | `website`, `api` | Yes | website: added on the website. api: added by an API key or a connected app. |
| `endpoint.api_version` | string | Yes |  |
| `signing_secret` | string | Yes | The new secret that signs every delivery, starting whsec_. It is shown only now: store it in the receiver's secret settings. |
| `previous_secret_expires_at` | string | Yes | When the previous secret stops signing deliveries: 24 hours after the rotation. |

## Example

```sh
curl -X POST "https://uetr.ai/api/v1/webhooks/3b1f8c2e-6a4d-4f5e-9c7b-2d8e1a0f4b6c/rotate-secret" \
  -H "Authorization: Bearer $UETR_API_KEY"
```

The answer:

```json
{
  "endpoint": {
    "id": "3b1f8c2e-6a4d-4f5e-9c7b-2d8e1a0f4b6c",
    "url": "hooks.slack.com/services/••••",
    "destination": "slack",
    "events": [
      "status_changed"
    ],
    "status": "active",
    "paused_at": null,
    "created_at": "2026-10-14T09:35:00.000Z",
    "created_by": "api",
    "api_version": "2026-10-14"
  },
  "signing_secret": "whsec_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
  "previous_secret_expires_at": "2026-10-15T09:40:00.000Z"
}
```

## Refusals

Besides the [access refusals](/docs/api/errors#access-refusals) every call can meet, this call can answer:

- [`read_only_credential`](/docs/api/errors#read_only_credential) (403): Read-only key or connection.
- [`machine_writes_disabled`](/docs/api/errors#machine_writes_disabled) (503): Changes are switched off.
- [`request_too_large`](/docs/api/errors#request_too_large) (413): Request too large.
- [`not_permitted`](/docs/api/errors#not_permitted) (403): Not permitted.
- [`not_found`](/docs/api/errors#not_found) (404): Not found.