curl --request PUT \
--url "https://directory.example.com/personas/example.com/operator" \
--header "Content-Type: application/json" \
--data '{
"action": "transfer_persona",
"persona": "example.com",
"current_operator_did": "did:openpayload:1111111111111111111111",
"new_operator_did": "did:openpayload:2222222222222222222222",
"new_controller_keys": [
"did:openpayload:2222222222222222222222#keys-1"
],
"new_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,
"new_operator_signer_key_id": "did:openpayload:2222222222222222222222#keys-1",
"nonce": "<current-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>",
"new_operator_signature": "<base64-new-operator-signature>",
"canonical_payload": "0x<current-controller-authorization-payload>",
"signature": "<base64-current-controller-signature>"
}'
Personas
Transfer a Persona operator
Submit the DNS-attested, two-party Persona transfer
curl --request PUT \
--url "https://directory.example.com/personas/example.com/operator" \
--header "Content-Type: application/json" \
--data '{
"action": "transfer_persona",
"persona": "example.com",
"current_operator_did": "did:openpayload:1111111111111111111111",
"new_operator_did": "did:openpayload:2222222222222222222222",
"new_controller_keys": [
"did:openpayload:2222222222222222222222#keys-1"
],
"new_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,
"new_operator_signer_key_id": "did:openpayload:2222222222222222222222#keys-1",
"nonce": "<current-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>",
"new_operator_signature": "<base64-new-operator-signature>",
"canonical_payload": "0x<current-controller-authorization-payload>",
"signature": "<base64-current-controller-signature>"
}'
Submit a prepared Persona transfer with the new operator’s acceptance signature and the current controller’s final authorization signature.
The final request repeats the verified intent and attestation so the Directory can reconstruct the exact signed payload.
acceptance_payload may be included but is not required at this step.
Request
Include the complete verified transfer intent, including the required echoedverification_expires_at, plus attestor, attestation_signature, new_operator_signature, and these fields:
string
required
Persona being transferred.
string
required
Verified, unused transfer challenge.
string
required
Exact payload returned by the prepare endpoint.
string
required
Current Persona-controller signature over the decoded
canonical_payload bytes.curl --request PUT \
--url "https://directory.example.com/personas/example.com/operator" \
--header "Content-Type: application/json" \
--data '{
"action": "transfer_persona",
"persona": "example.com",
"current_operator_did": "did:openpayload:1111111111111111111111",
"new_operator_did": "did:openpayload:2222222222222222222222",
"new_controller_keys": [
"did:openpayload:2222222222222222222222#keys-1"
],
"new_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,
"new_operator_signer_key_id": "did:openpayload:2222222222222222222222#keys-1",
"nonce": "<current-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>",
"new_operator_signature": "<base64-new-operator-signature>",
"canonical_payload": "0x<current-controller-authorization-payload>",
"signature": "<base64-current-controller-signature>"
}'
Response
202 Response
{
"status": "accepted",
"persona": "example.com",
"current_operator_did": "did:openpayload:1111111111111111111111",
"new_operator_did": "did:openpayload:2222222222222222222222",
"extrinsic": "apply_persona_with_proof",
"operation": "transfer_persona",
"tx_hash": "<transaction-hash>"
}
202 Accepted confirms submission, not finalization. Read the Persona until the new operator_did, controller set, DNS timestamps, constraints, and revision are finalized.
Transfer clears the previous Persona policy. Publish a new Persona policy under the new controller if one is required. If delivery_constraints was omitted from the transfer intent, the Persona has no Persona-specific constraints and delivery falls through to the remaining effective constraints.
Straight to the point
PUT /personas/{persona}/operator
- Requires fresh DNS verification, new-operator acceptance, and current-controller authorization
- Consumes the transfer challenge on accepted submission
- Replaces the operator and controller set
- Clears the previous Persona policy

