curl --request POST \
--url "https://directory.example.com/personas/example.com/dns-challenges/<challenge-id>/verify" \
--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"
}'
Personas
Verify a Persona DNS challenge
Verify the TXT record and prepare an attested canonical Persona payload for local signing
curl --request POST \
--url "https://directory.example.com/personas/example.com/dns-challenges/<challenge-id>/verify" \
--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"
}'
After publishing the Persona TXT record, submit the intended registration or renewal. The Directory checks DNS, validates the intent against finalized state, obtains a chain-compatible Directory attestation, and returns the exact canonical payload your operator key must sign.
This step does not register or renew the Persona. Do not sign a locally reconstructed payload; sign the decoded bytes returned in
For renewal, use
Decode
canonical_payload.
Request
string
required
Canonical Persona from the challenge.
string
required
Challenge ID returned by the challenge endpoint.
string
Optional body copy of the canonical path Persona. When supplied, it must match after normalization.
string
required
register_persona or renew_persona. It must equal the challenge action.string
required
Operator DID bound to the challenge. It must be active in finalized chain state.
string[]
One through eight unique signing-key IDs published by
operator_did. Required for registration. Renewal must omit this field or repeat the finalized set exactly.integer
Required for registration and must equal
1. Renewal cannot change the finalized value.object
Optional complete requested limits. Omit
effective_ttl_seconds. A renewal that omits this field retains the finalized Persona constraints.string
Optional body copy of the path challenge. When supplied, it must match.
string
required
Current
operator_nonce returned with the challenge or by the Persona nonce endpoint.string
required
Short-lived Unix-millisecond or ISO-8601 expiration for the prepared operation.
string
required
Operator-DID verification-method ID that will sign the returned canonical payload. It must also be an active Persona controller for renewal.
integer
required
Unix-millisecond DNS-verification expiration. It must be in the future and cannot be more than 90 days away.
curl --request POST \
--url "https://directory.example.com/personas/example.com/dns-challenges/<challenge-id>/verify" \
--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"
}'
renew_persona. Omit controllers and constraints to retain their finalized values, or repeat the existing controllers exactly. Renewal cannot rotate controllers.
Response
200 Response
{
"status": "verified",
"challenge_id": "<challenge-id>",
"persona": "example.com",
"operator_did": "did:openpayload:1111111111111111111111",
"action": "register_persona",
"challenge_nonce": "0",
"record_name": "_openpayload-persona.example.com",
"record_type": "TXT",
"record_value": "openpayload-persona-v1=<challenge>",
"expires_at": "2026-09-17T18:00:00Z",
"dns_proof_hash": "0x<64-hex-dns-proof-hash>",
"verification_expires_at": 1796083200000,
"operator_nonce": "0",
"canonical_payload": "0x<canonical-payload>",
"attestor": "0x<directory-attestor-account>",
"attestation_signature": "0x<directory-attestation-signature>"
}
canonical_payload, sign those bytes with signer_key_id, and submit the result to PUT /personas/{persona} before the challenge and valid_until expire. Repeat the echoed verification_expires_at exactly.
Straight to the point
POST /personas/{persona}/dns-challenges/{challenge_id}/verify
- DNS TXT record must already be visible
- Response prepares but does not submit the chain operation
- Sign the returned canonical bytes exactly
- DNS or attestation failure does not consume a successful registration

