> ## 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.

# POST /v1/providers/ownership-challenges — Create Challenge

> Issue a short-lived DID ownership challenge to prove key control before registering a provider or rotating its DID key on this node.

Ownership challenges let the node verify that you control the private key behind a DID before allowing [provider registration](/api/providers/register) or [key rotation](/api/providers/rotate-key).

The workflow is:

1. **POST** to create a challenge — the node returns a short-lived string to sign.
2. Sign the `challenge` string with the Ed25519 private key for your DID.
3. Submit the `challenge_id` and your signature in the subsequent provider register or rotate-key request.

***

## Create an ownership challenge

### `POST /v1/providers/ownership-challenges`

```bash theme={null}
curl -X POST http://your-node:8042/v1/providers/ownership-challenges \
  -H 'content-type: application/json' \
  -d '{
    "provider_did": "did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa",
    "operation": "register"
  }'
```

### Body parameters

<ParamField body="provider_did" type="string" required>
  The DID you will prove ownership of (e.g. `"did:key:z6Mk…"`). Must match the DID you intend to use when registering or rotating.
</ParamField>

<ParamField body="operation" type="string" required>
  The operation this challenge authorises. Either `"register"` (new provider) or `"rotate_key"` (key rotation on an existing provider).
</ParamField>

<ParamField body="provider_id" type="string">
  Required when `operation` is `"rotate_key"`. The `provider_id` of the existing provider whose key you are rotating.
</ParamField>

### Response

Returns a `ProviderOwnershipChallenge` with status `201 Created`.

<ResponseField name="challenge_id" type="string (UUID)">
  Unique identifier for this challenge. Pass this as `ownership_challenge_id` in the subsequent request.
</ResponseField>

<ResponseField name="provider_id" type="string">
  The provider ID associated with this challenge.
</ResponseField>

<ResponseField name="provider_did" type="string">
  The DID this challenge was issued for.
</ResponseField>

<ResponseField name="operation" type="string">
  Either `"register"` or `"rotate_key"`.
</ResponseField>

<ResponseField name="challenge" type="string">
  The raw string you must sign with the Ed25519 private key for `provider_did`. Pass the resulting base64 signature as `ownership_signature`.
</ResponseField>

<ResponseField name="issued_at" type="string">
  ISO 8601 timestamp of when the challenge was created.
</ResponseField>

<ResponseField name="expires_at" type="string">
  ISO 8601 timestamp after which this challenge is no longer valid. Default TTL is 300 seconds.
</ResponseField>

<ResponseField name="completed_at" type="string">
  ISO 8601 timestamp of when the challenge was successfully consumed. Omitted until the challenge is used.
</ResponseField>

### Status codes

| Code              | Meaning                                                   |
| ----------------- | --------------------------------------------------------- |
| `201 Created`     | Challenge issued successfully.                            |
| `400 Bad Request` | Invalid `provider_did` format or missing required fields. |

### Example response

```json theme={null}
{
  "challenge_id": "b3d2e1f0-1234-5678-abcd-000000000001",
  "provider_id": "acme-labs",
  "provider_did": "did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa",
  "operation": "register",
  "challenge": "servicenet-challenge:register:acme-labs:1736934000000",
  "issued_at": "2025-01-15T10:00:00Z",
  "expires_at": "2025-01-15T10:05:00Z"
}
```

***

## Retrieve an ownership challenge

### `GET /v1/providers/ownership-challenges/:challenge_id`

```bash theme={null}
curl http://your-node:8042/v1/providers/ownership-challenges/b3d2e1f0-1234-5678-abcd-000000000001
```

### Path parameters

<ParamField path="challenge_id" type="string (UUID)" required>
  The `challenge_id` returned when you created the challenge.
</ParamField>

### Response

Returns the same `ProviderOwnershipChallenge` object described above. The `completed_at` field is set once the challenge has been successfully used.

### Status codes

| Code            | Meaning                                            |
| --------------- | -------------------------------------------------- |
| `200 OK`        | Challenge found.                                   |
| `404 Not Found` | No challenge with the given `challenge_id` exists. |

### Example response

```json theme={null}
{
  "challenge_id": "b3d2e1f0-1234-5678-abcd-000000000001",
  "provider_id": "acme-labs",
  "provider_did": "did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa",
  "operation": "register",
  "challenge": "servicenet-challenge:register:acme-labs:1736934000000",
  "issued_at": "2025-01-15T10:00:00Z",
  "expires_at": "2025-01-15T10:05:00Z",
  "completed_at": "2025-01-15T10:01:30Z"
}
```
