> ## Documentation Index
> Fetch the complete documentation index at: https://hs-df36fa00.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Rotate Key — POST /v1/providers/:provider_id/rotate-key

> Update a provider's DID key while keeping the same provider ID. Requires an ownership challenge signature when challenges are enabled.

Replaces the DID associated with an existing provider without changing its `provider_id`. Use this when you need to rotate cryptographic keys while preserving registry continuity.

When the node requires ownership challenges, first [create a challenge](/api/providers/ownership-challenge) with `operation: "rotate_key"` and `provider_id` set to the target provider, sign the returned `challenge` string, then include both fields in this request.

## Request

```bash theme={null}
curl -X POST http://your-node:8042/v1/providers/acme-labs/rotate-key \
  -H 'content-type: application/json' \
  -d '{
    "new_provider_did": "did:key:z6MkpTHR8VNsBxYAAWHut2GeaddA1bbm8CLcfJ4pKzvmWwLp",
    "reason": "Scheduled key rotation",
    "ownership_challenge_id": "b3d2e1f0-1234-5678-abcd-000000000002",
    "ownership_signature": "<BASE64_ED25519_SIGNATURE>"
  }'
```

### Path parameters

<ParamField path="provider_id" type="string" required>
  The identifier of the provider whose DID you are rotating.
</ParamField>

### Body parameters

<ParamField body="new_provider_did" type="string" required>
  The new DID that will replace the current one (e.g. `"did:key:z6Mk…"`).
</ParamField>

<ParamField body="reason" type="string">
  Optional human-readable reason for the rotation (e.g. `"Scheduled key rotation"`). Stored in the audit log.
</ParamField>

<ParamField body="ownership_challenge_id" type="string (UUID)">
  The `challenge_id` from a `"rotate_key"` ownership challenge. Required when the node enforces ownership challenges.
</ParamField>

<ParamField body="ownership_signature" type="string">
  Base64-encoded Ed25519 signature of the challenge string, signed with the private key corresponding to `new_provider_did`. Required when `ownership_challenge_id` is provided.
</ParamField>

## Response

Returns the updated `ProviderRecord` on success.

<ResponseField name="schema_version" type="integer">
  Protocol schema version. Currently `1`.
</ResponseField>

<ResponseField name="provider_id" type="string">
  The provider identifier (unchanged by this operation).
</ResponseField>

<ResponseField name="provider_did" type="string">
  The newly registered DID.
</ResponseField>

<ResponseField name="display_name" type="string">
  Human-readable display name (unchanged by this operation).
</ResponseField>

<ResponseField name="status" type="string">
  Provider lifecycle status. Returns `"active"` after a successful rotation.
</ResponseField>

<ResponseField name="registered_at" type="string">
  ISO 8601 timestamp of original provider registration (unchanged).
</ResponseField>

## Status codes

| Code              | Meaning                                                             |
| ----------------- | ------------------------------------------------------------------- |
| `200 OK`          | Key rotated successfully. Returns the updated `ProviderRecord`.     |
| `400 Bad Request` | Invalid DID format, invalid or expired challenge, or bad signature. |
| `404 Not Found`   | No provider with the given `provider_id` exists.                    |

## Example response

```json theme={null}
{
  "schema_version": 1,
  "provider_id": "acme-labs",
  "provider_did": "did:key:z6MkpTHR8VNsBxYAAWHut2GeaddA1bbm8CLcfJ4pKzvmWwLp",
  "display_name": "Acme Labs",
  "status": "active",
  "registered_at": "2025-01-15T10:00:00Z"
}
```
