# POST /v1/organizations/:orgId/api-keys/:keyId/rotate (/docs/api/reference/organizations/api-keys/rotate)



<Endpoint method="POST" path="/v1/organizations/{orgId}/api-keys/{keyId}/rotate" auth="Bearer" scope="org:admin" phase="1" />

To roll a customer's credential without an outage, rotate the child key. You call this with your parent (`org:admin`) key. Rotation mints a **brand-new key** (new id, new secret) carrying the same scopes, env, and tier as the old one - and the **old secret keeps working for a 24-hour grace window**. That overlap is the point: deploy the new secret across the customer's fleet at your own pace, and the old one stops automatically when the window closes.

This is distinct from rotating your own [parent key](/docs/api/reference/api-keys/rotate), which replaces the secret in place and kills the old one instantly. Child rotation is dual-secret by design.

A key can be rotated **once**. Once you rotate a key it's superseded by its replacement, and rotating that same (superseded) key again returns `409 CONFLICT` - rotate the current key instead. The chain rolls forward cleanly: K → K2 → K3, each link rotating the live key, never a retired one.

The new plaintext secret is returned **once**, in this response. Store it before you do anything else.

<Parameters
  title="Path"
  rows="[
  { name: 'orgId', type: 'string (org_…)', required: true, description: 'The child organization that owns the key. Must be a direct child of your org.' },
  { name: 'keyId', type: 'string (key_…)', required: true, description: 'The key to rotate. Must belong to this child org, must be active (not revoked or killed), and must be the current key - not one that has already been rotated.' },
]"
/>

<Parameters
  title="Headers"
  rows="[
  { name: 'Idempotency-Key', type: 'string (UUID)', required: false, description: 'Strongly recommended. A replay returns the SAME new secret - without it, a retry mints a second replacement and your first secret goes stale.' },
]"
/>

## Example [#example]

```bash
NEW_SECRET=$(curl -s -X POST \
  https://api.layers.com/v1/organizations/org_d4e5f6a7-8b9c-4d0e-9f2a-3b4c5d6e7f80/api-keys/key_c2037bb9.../rotate \
  -H "Authorization: Bearer $LAYERS_PARENT_KEY" \
  -H "Idempotency-Key: $(uuidgen)" | jq -r .secret)

# Deploy NEW_SECRET to the customer's services within 24h.
# The old secret keeps working until then, so there's no flap.
```

<Response status="200" description="OK - new key minted, secret returned once">
  ```json
  {
    "apiKey": {
      "id": "key_9a44e1f0-...",
      "organizationId": "org_d4e5f6a7-8b9c-4d0e-9f2a-3b4c5d6e7f80",
      "name": "acme-content-sync",
      "prefix": "lp_live_TUVWXYZ23456789",
      "env": "live",
      "scopes": ["content:read", "content:write"],
      "rateLimitTier": "standard",
      "status": "active",
      "createdAt": "2026-06-03T20:31:10.552Z",
      "lastUsedAt": null,
      "rotatedAt": null,
      "revokedAt": null,
      "graceUntil": null,
      "supersededBy": null
    },
    "secret": "lp_live_...",
    "warning": "Store this secret now. It cannot be retrieved again. Rotate the key if it's lost."
  }
  ```
</Response>

The response is the **new** key - the customer's go-forward credential. To observe the old key's grace window, [list the child's keys](/docs/api/reference/organizations/api-keys/list): the old row now carries `graceUntil` (when its secret stops) and `supersededBy` (the new key's id).

## Rotation runbook [#rotation-runbook]

<Steps>
  <Step>
    **Rotate**

     with a fresh 

    `Idempotency-Key`

    . Grab 

    `secret`

     from the response - the new credential.
  </Step>

  <Step>
    **Deploy the new secret**

     to every service the customer runs, within 24 hours. The old secret is still live, so callers don't flap during the rollout.
  </Step>

  <Step>
    **Verify**

     with 

    `GET /v1/whoami`

     using the new secret. A 200 confirms it end-to-end.
  </Step>

  <Step>
    **Let the old secret expire.**

     At 

    `graceUntil`

     it stops on its own - no second call needed. To cut it off sooner, 

    [delete](/docs/api/reference/organizations/api-keys/delete)

     the old key.
  </Step>
</Steps>

<Callout type="warn">
  The grace window never overrides a kill switch. If you or the customer's org is suspended or archived, the old (and new) secret is rejected with `503 KILL_SWITCH` regardless of `graceUntil`. Grace only postpones the old secret's normal expiry - it never resurrects access that ops has cut.
</Callout>

## Errors [#errors]

| Status | Code                   | When                                                                                                                                         |
| ------ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| 404    | `NOT_FOUND`            | `:orgId` isn't your child, OR `:keyId` isn't that child's key, OR the key is already revoked / killed (terminal state stays un-confirmable). |
| 409    | `CONFLICT`             | The key has already been rotated (it's superseded by a newer key). Rotate the current key instead.                                           |
| 422    | `VALIDATION`           | Malformed `:orgId` or `:keyId`.                                                                                                              |
| 409    | `IDEMPOTENCY_CONFLICT` | `Idempotency-Key` reused with a different body.                                                                                              |
| 503    | `KILL_SWITCH`          | Your key or org is suspended; or the child org is suspended/archived.                                                                        |

## See also [#see-also]

* [Mint a child key](/docs/api/reference/organizations/api-keys/mint) - create the original key.
* [List](/docs/api/reference/organizations/api-keys/list) - read `graceUntil` / `supersededBy` on the old key.
* [Delete](/docs/api/reference/organizations/api-keys/delete) - kill the old secret immediately instead of waiting out the grace.
* [API keys → rotation grace window](/docs/api/concepts/api-keys#rotation-grace-window) - the concept and playbook.
