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

# Register a Persona

> Register a collective name, with DNS proof when the name is a domain

A Persona is a public name for a collective or policy operator. It can own delivery constraints and one delivery policy independently of a recipient DID. OpenPayload does not track Persona membership. A sender selects a Persona in the recipient address because it wants that Persona's policy applied.

A Persona is not an alias. Use it in the optional suffix of a delivery target, such as `did:openpayload:...@example.com`.

The deployed spec 123 services accept domain-shaped Personas and single-label names such as `compliance`. Single-label names do not claim a domain and need no DNS challenge. The DNS flow below is for a domain-shaped Persona.

## Single-label names

For a single-label name, [prepare a DID-signed registration](/api-reference/directory/personas/prepare-named), sign the returned `canonical_payload` with an operator DID controller key, and [submit it](/api-reference/directory/personas/register-named). Use action `register_named_persona`, the operator DID, controller keys, threshold `1`, the current operator nonce, and a future `valid_until`. No DNS step is involved.

The current Directory API does not expose the operator nonce for a first Persona registration. Read that counter from chain state, or use `operator_nonce` from an existing Persona under the same operator DID. `GET /personas/{persona}/nonces` returns `404` for an unregistered name.

Persona policies can define routing, archive forks, or other explicit actions. A policy does not itself prove that a recipient belongs to the collective; the Persona operator handles membership outside OpenPayload.

## Domain-shaped names

The canonical DNS name is globally unique in chain state. A new registration is rejected when that Persona already exists; an existing Persona must use the renewal or authenticated transfer flow instead.

## Before you begin

You need:

* A canonical DNS name you control.
* An active operator DID.
* An authorized private signing key for that DID.
* Permission to publish a TXT record below the domain.

The Directory normalizes an internationalized domain to its lowercase ASCII IDNA form and removes a trailing dot. A Persona must be a fully qualified name with at least two DNS labels. URLs, paths, ports, wildcard names, IP addresses, and names with a numeric-only top-level label are not Personas.

## 1. Request a DNS challenge

```bash theme={null}
curl --request POST \
  --url "https://directory.example.com/personas/example.com/dns-challenges" \
  --header "Content-Type: application/json" \
  --data '{
    "operator_did": "did:openpayload:1111111111111111111111"
  }'
```

The response supplies the exact TXT record name and value. A challenge is short-lived, single-use, and bound to the Persona, operator DID, network, and nonce.

## 2. Publish the TXT record

Publish the returned value exactly:

```text theme={null}
_openpayload-persona.example.com TXT "openpayload-persona-v1=<challenge>"
```

DNS propagation time depends on your DNS provider and the record's time to live.

## 3. Verify DNS and prepare the payload

Send the complete unsigned registration intent to the verification endpoint. Use the `operator_nonce` returned with the challenge.

```json theme={null}
{
  "action": "register_persona",
  "persona": "example.com",
  "operator_did": "did:openpayload:1111111111111111111111",
  "controller_keys": [
    "did:openpayload:1111111111111111111111#keys-1"
  ],
  "controller_threshold": 1,
  "challenge_id": "<challenge-id>",
  "delivery_constraints": {
    "requested_cache_seconds": 86400,
    "max_http_envelope_bytes": 26214400,
    "max_unchunked_message_bytes": 16777216,
    "max_chunk_bytes": 2097152,
    "max_replicas": 2
  },
  "verification_expires_at": 1796083200000,
  "nonce": "<operator-nonce>",
  "valid_until": "<epoch-milliseconds>",
  "signer_key_id": "did:openpayload:1111111111111111111111#keys-1"
}
```

Post that body to:

```http theme={null}
POST /personas/example.com/dns-challenges/{challenge_id}/verify
```

The Directory checks the TXT record and returns its DNS attestation plus the exact `canonical_payload` for this intent.

## 4. Sign and submit

Decode `canonical_payload` and sign those exact bytes locally with `signer_key_id`. Submit the full intent again, including the Directory attestation returned by verification, followed by the canonical payload and your signature:

```json theme={null}
{
  "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-signature>"
}
```

Send this body to `PUT /personas/example.com`. `202 Accepted` means the request was submitted to the chain. Read the Persona until its revision and verification timestamps reflect finalized state.

## Renewal and controller changes

Renew DNS verification before `verification_expires_at`. Choose an explicit future expiration when verifying the intent; it can be at most 90 days away:

* Create a challenge with action `renew_persona`.
* Publish and verify the new TXT value.
* Sign the returned canonical payload and submit it through `PUT /personas/{persona}`.

The existing operator can also use this renewal flow to reactivate an expired or revoked Persona. Policy, controller-rotation, constraint, and transfer mutations require the Persona to be active; renewal is the recovery path.

Use `PUT /personas/{persona}/controllers` to change controller keys. Persona v1 requires a threshold of `1`; the controller set may contain one through eight operator-DID signing keys, but each update uses one active-controller signature. The signing key must remain in the new set, so key removal is staged: add a replacement, wait for finalization, then use that replacement to authorize removal of the old key.

## Transfer to a new operator

An operator transfer requires fresh DNS control plus authorization from both parties:

1. Create a challenge with `POST /personas/{persona}/transfer/dns-challenges` and publish its TXT value.
2. Verify the complete transfer intent with `POST /personas/{persona}/transfer/dns-challenges/{challenge_id}/verify`.
3. Have the new operator sign the returned `acceptance_payload`, then send that signature to the matching `/prepare` endpoint.
4. Have a current Persona controller sign the returned `canonical_payload`, then submit both signatures with `PUT /personas/{persona}/operator`.

The new controller set must contain one through eight signing keys published by the new operator DID, and `new_controller_threshold` must equal `1`. The DNS verification can remain valid for at most 90 days.

Transfer clears the old Persona policy so the previous operator cannot leave routing instructions behind. Publish a new policy after finalization if required. Transfer also replaces Persona-specific delivery constraints; omit `delivery_constraints` only when the Persona should fall through to DID and network constraints.

Use `DELETE /personas/{persona}` with action `revoke_persona` to deactivate it. A revoked or expired Persona cannot win policy resolution.

DNS proof establishes control of the domain at verification time. It does not establish the identity, reputation, or trustworthiness of the organization operating it.

## Straight to the point

```text theme={null}
Challenge: POST /personas/{persona}/dns-challenges
Single-label prepare: POST /personas/{persona}/named/prepare
Single-label register: PUT /personas/{persona}/named
Verify: POST /personas/{persona}/dns-challenges/{challenge_id}/verify
Register or renew: PUT /personas/{persona}
Read: GET /personas/{persona}
Rotate controllers: PUT /personas/{persona}/controllers
Begin transfer: POST /personas/{persona}/transfer/dns-challenges
Verify transfer: POST /personas/{persona}/transfer/dns-challenges/{challenge_id}/verify
Prepare transfer: POST /personas/{persona}/transfer/dns-challenges/{challenge_id}/prepare
Submit transfer: PUT /personas/{persona}/operator
Revoke: DELETE /personas/{persona}
```


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