> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openpayload.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Submit a Persona registration or renewal

> Sign and submit the canonical DNS-attested Persona payload prepared by a Directory

Submit the final operator signature for a Persona registration or DNS renewal. You must first complete [Verify a Persona DNS challenge](/api-reference/directory/personas/verify-dns-challenge) through the same Directory deployment.

The verification response contains a `canonical_payload` that already binds the DNS attestation, operation, nonces, operator DID, constraints, and expiration. A registration payload also binds the proposed controllers and threshold. A renewal preserves the finalized controller set instead of encoding a replacement; use the controller-rotation endpoint for changes. Decode and sign the returned bytes locally. Submit the bound intent fields again so the Directory can reconstruct and compare the payload; do not alter them between verification and submission.

Persona v1 requires `controller_threshold` to equal `1`. The controller set can contain more than one authorized verification-method ID, but each current update carries one active-controller signature.

## Request

<ParamField path="persona" type="string" required>
  Persona prepared by the verified challenge.
</ParamField>

<ParamField body="persona" type="string">
  Optional body copy of the path Persona. When supplied, it must match after normalization.
</ParamField>

<ParamField body="challenge_id" type="string" required>
  Verified, unused challenge ID.
</ParamField>

<ParamField body="action" type="string" required>
  `register_persona` or `renew_persona`, exactly as verified.
</ParamField>

<ParamField body="operator_did" type="string" required>
  Operator DID bound to the DNS challenge.
</ParamField>

<ParamField body="controller_keys" type="string[]">
  Controller set from the verified intent. Required for registration; renewal must omit it or repeat the finalized set exactly.
</ParamField>

<ParamField body="controller_threshold" type="integer">
  Must equal `1` when supplied.
</ParamField>

<ParamField body="delivery_constraints" type="object">
  Requested constraints from the verified intent. Omit `effective_ttl_seconds`.
</ParamField>

<ParamField body="verification_expires_at" type="integer" required>
  Unix-millisecond DNS-verification expiration from the verified intent.
</ParamField>

<ParamField body="nonce" type="string" required>
  Operator nonce used to build the verified intent.
</ParamField>

<ParamField body="valid_until" type="string" required>
  Authorization expiration used to build the verified intent.
</ParamField>

<ParamField body="attestor" type="string" required>
  Directory attestor account returned by challenge verification.
</ParamField>

<ParamField body="attestation_signature" type="string" required>
  Directory attestation signature returned by challenge verification.
</ParamField>

<ParamField body="canonical_payload" type="string" required>
  Exact value returned by challenge verification, encoded as `0x`-prefixed hexadecimal.
</ParamField>

<ParamField body="signer_key_id" type="string" required>
  Same verification-method ID declared during verification.
</ParamField>

<ParamField body="signature" type="string" required>
  Ed25519 signature over the decoded canonical payload bytes, encoded as hexadecimal or Base64.
</ParamField>

<RequestExample>
  ```bash Request theme={null}
  curl --request PUT \
    --url "https://directory.example.com/personas/example.com" \
    --header "Content-Type: application/json" \
    --data '{
      "action": "register_persona",
      "persona": "example.com",
      "operator_did": "did:openpayload:1111111111111111111111",
      "controller_keys": [
        "did:openpayload:1111111111111111111111#keys-1"
      ],
      "controller_threshold": 1,
      "delivery_constraints": {
        "requested_cache_seconds": 86400,
        "max_http_envelope_bytes": 26214400,
        "max_unchunked_message_bytes": 16777216,
        "max_chunk_bytes": 2097152,
        "max_replicas": 2
      },
      "challenge_id": "<challenge-id>",
      "verification_expires_at": 1796083200000,
      "nonce": "<operator-nonce>",
      "valid_until": "<epoch-milliseconds>",
      "signer_key_id": "did:openpayload:1111111111111111111111#keys-1",
      "attestor": "0x<directory-attestor-account>",
      "attestation_signature": "0x<directory-attestation-signature>",
      "canonical_payload": "0x<canonical-payload-from-verification>",
      "signature": "<base64-ed25519-signature>"
    }'
  ```
</RequestExample>

## Response

```json 202 Response theme={null}
{
  "status": "accepted",
  "persona": "example.com",
  "operator_did": "did:openpayload:1111111111111111111111",
  "extrinsic": "apply_persona_with_proof",
  "operation": "register_persona",
  "tx_hash": "<transaction-hash>"
}
```

For renewal, `operation` is `renew_persona`. The finalized renewal can reactivate an expired or revoked Persona under its existing operator. `202 Accepted` confirms chain submission, not finalization. Read the Persona until its `revision`, `active`, `verified_at`, and `verification_expires_at` reflect the finalized operation.

## Straight to the point

```http theme={null}
PUT /personas/{persona}
```

* Prerequisite: verified DNS challenge through the same Directory deployment
* Sign: decoded `canonical_payload` returned by verification
* Challenge: single-use
* Accepted submission: `202`


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.