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

# Prepare a Persona transfer

> Bind the new operator acceptance and prepare the current controller authorization payload

Submit the verified transfer intent with the new operator's acceptance signature. The Directory binds that signature and the DNS attestation into the outer `canonical_payload` for an active current Persona controller to sign. The chain verifies the new-operator signature when the final transfer is submitted.

Repeat the Persona, operators, new controller set, constraints, challenge and operator nonces, new-operator signer, and `verification_expires_at` from verification. Those values are bound by `acceptance_payload` and a mismatch is rejected. The current controller may choose a fresh active `signer_key_id` and future `valid_until` for this outer authorization; repeat those exact outer values in the final transfer request.

## Request

In addition to the complete body documented by [Verify a Persona transfer challenge](/api-reference/directory/personas/verify-transfer-challenge), include these fields:

<ParamField body="acceptance_payload" type="string" required>
  Exact value returned by transfer verification.
</ParamField>

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

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

<ParamField body="new_operator_signature" type="string" required>
  Signature by `new_operator_signer_key_id` over the decoded `acceptance_payload` bytes.
</ParamField>

<RequestExample>
  ```bash Request theme={null}
  curl --request POST \
    --url "https://directory.example.com/personas/example.com/transfer/dns-challenges/<challenge-id>/prepare" \
    --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",
      "acceptance_payload": "0x<new-operator-acceptance-payload>",
      "attestor": "0x<directory-attestor-account>",
      "attestation_signature": "0x<directory-attestation-signature>",
      "new_operator_signature": "<base64-ed25519-signature>"
    }'
  ```
</RequestExample>

## Response

```json 200 Response theme={null}
{
  "challenge_id": "<challenge-id>",
  "persona": "example.com",
  "action": "transfer_persona",
  "challenge_nonce": "3",
  "operator_nonce": "7",
  "record_name": "_openpayload-persona.example.com",
  "record_type": "TXT",
  "record_value": "openpayload-persona-v1=<challenge>",
  "expires_at": "2026-09-17T18:00:00Z",
  "current_operator_did": "did:openpayload:1111111111111111111111",
  "new_operator_did": "did:openpayload:2222222222222222222222",
  "verification_expires_at": 1796083200000,
  "status": "prepared",
  "canonical_payload": "0x<current-controller-authorization-payload>",
  "signer_key_id": "did:openpayload:1111111111111111111111#keys-1"
}
```

Decode `canonical_payload` and sign those bytes with the returned current `signer_key_id`. The resulting signature is the `signature` field for the final transfer request.

## Straight to the point

```http theme={null}
POST /personas/{persona}/transfer/dns-challenges/{challenge_id}/prepare
```

* New operator signs `acceptance_payload`
* Current Persona controller signs the returned `canonical_payload`
* Preparing does not consume the challenge or submit the transfer


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