# POST /v1/webhook-endpoints/:endpointId/rotate-secret (/docs/api/reference/webhooks/rotate-secret)



<Endpoint method="POST" path="/v1/webhook-endpoints/{endpointId}/rotate-secret" auth="X-Api-Key" phase="1" />

Rotates the endpoint's signing secret. The previous secret remains valid for 24 hours (`previousSecretExpiresAt` in the response) so receivers can dual-verify during cutover without dropping deliveries. During the overlap window, `X-Layers-Signature` includes multiple `v1=<mac>` entries — one for each active secret — and your verifier should accept a match from any of them.

<Parameters
  title="Headers"
  rows="[
  { name: 'Idempotency-Key', type: 'string (UUID)', description: 'Replays within 24h.' },
]"
/>

## Example [#example]

```bash
curl -X POST https://api.layers.com/v1/webhook-endpoints/d4c71b62-.../rotate-secret \
  -H "X-Api-Key: $LAYERS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

<Response status="200" description="OK — new signing secret returned once">
  ```json
  {
    "endpointId": "d4c71b62-7f08-4dc9-9d2c-8f7e2b9c4411",
    "signingSecret": "whsec_new...",
    "previousSecretExpiresAt": "2026-04-21T18:28:00.000Z",
    "warning": "Signing secret shown once. The previous secret remains valid for 24 hours — dual-verify both in your handler during cutover."
  }
  ```
</Response>

## Cutover pattern [#cutover-pattern]

1. Call rotate. Store the new `signingSecret` under a different key from your current one — e.g., `LAYERS_WEBHOOK_SECRET_NEW` + `LAYERS_WEBHOOK_SECRET`.
2. Update your verifier to accept a signature from EITHER secret.
3. Deploy. Watch for deliveries for 24h; they'll arrive signed with both MACs.
4. After 24h the old secret expires server-side. Drop it from your config.

## Errors [#errors]

| Status | Code                   | When                                                                                         |
| ------ | ---------------------- | -------------------------------------------------------------------------------------------- |
| 404    | `NOT_FOUND`            | Endpoint not owned by the calling org.                                                       |
| 409    | `IDEMPOTENCY_CONFLICT` | Idempotency-Key reused with a different body (empty-body reuse returns the cached response). |
