> ## 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 DID update

> Validate a DID change and get the exact authorization bytes to sign locally

Prepare an existing DID's authorized update before signing it. The Directory checks the current chain record, validates the proposed fields, reads the operation's nonce when needed, and builds the canonical authorization payload. Preparation does **not** submit a transaction or change the DID.

Your private key stays with your client. Decode the returned `payload_to_sign` hex into bytes, sign those bytes with an authorized Ed25519 key, and add the Base64 signature to the returned `request` object. Submit that object to the public endpoint for the selected action, such as [Add a DID service](/api-reference/directory/document/add-service). After a `202 Accepted` submission, check the [registration status](/api-reference/directory/dids/registration-status) and verify the expected record version or document change; an existing DID can already have `registration_status: "confirmed"` before your update.

## Request

<ParamField path="did" type="string" required>
  The complete, URL-encoded DID to update. It must already exist and be active.
</ParamField>

<ParamField body="action" type="string" required>
  The operation's action value, such as `AddService`, `add_alias`, or `deactivate_did`. Use the value documented by the corresponding mutation endpoint.
</ParamField>

<ParamField body="did" type="string">
  If supplied, this DID must match the path.
</ParamField>

<ParamField body="signer_key_id" type="string">
  The authorized verification-method ID, or `root` for the DID root key. Defaults to `root`.
</ParamField>

<ParamField body="valid_until" type="string">
  Authorization expiry as unsigned Unix epoch milliseconds. For nonce-based operations, it must be in the next hour. If omitted, the Directory selects a value about five minutes ahead.
</ParamField>

Include the fields required by the action. For example, `AddService` needs a `service` object. Full document replacement uses `action: "replace_document"` and a complete `document`; the Directory prepares its document proof with a timestamp instead of a nonce-based payload.

<RequestExample>
  ```bash Request theme={null}
  curl --request POST \
    --url "https://directory.example.com/dids/did%3Aopenpayload%3A1111111111111111111111/prepare" \
    --header "Content-Type: application/json" \
    --data '{
      "action": "AddService",
      "signer_key_id": "root",
      "service": {
        "id": "did:openpayload:1111111111111111111111#cache",
        "type": "OpenPayloadCacheService",
        "serviceEndpoint": ["https://cache.example.com"],
        "authorization": ["did:openpayload:1111111111111111111111#root"]
      }
    }'
  ```
</RequestExample>

## Response

<ResponseField name="did" type="string" required>
  The DID being updated.
</ResponseField>

<ResponseField name="action" type="string" required>
  The selected operation.
</ResponseField>

<ResponseField name="previous_version" type="integer" required>
  The version of the DID record read during preparation.
</ResponseField>

<ResponseField name="nonce_domain" type="string">
  The nonce counter used for this action, such as `document_nonce` or `control_nonce`. Absent for full document replacement.
</ResponseField>

<ResponseField name="payload_to_sign" type="string" required>
  `0x`-prefixed hex for the exact bytes to sign. Decode the hex before signing; do not sign the printed characters or JSON.
</ResponseField>

<ResponseField name="request" type="object" required>
  Validated public request fields for the corresponding mutation endpoint. Add a Base64 Ed25519 `signature` before submitting. For nonce-based operations, `request.canonical_payload` contains the same hex bytes as `payload_to_sign`.
</ResponseField>

<ResponseExample>
  ```json 200 Response theme={null}
  {
    "did": "did:openpayload:1111111111111111111111",
    "action": "AddService",
    "previous_version": 1,
    "nonce_domain": "document_nonce",
    "payload_to_sign": "0x<hex-encoded-authorization-bytes>",
    "request": {
      "did": "did:openpayload:1111111111111111111111",
      "action": "AddService",
      "service": {
        "id": "did:openpayload:1111111111111111111111#cache",
        "type": "OpenPayloadCacheService",
        "serviceEndpoint": ["https://cache.example.com"],
        "authorization": ["did:openpayload:1111111111111111111111#root"]
      },
      "valid_until": "<future-epoch-milliseconds>",
      "signer_key_id": "root",
      "nonce": "7",
      "canonical_payload": "0x<same-hex-encoded-authorization-bytes>"
    }
  }
  ```
</ResponseExample>

If the DID changes after preparation, its nonce can become stale. Prepare again before signing or submitting. Chain lookup failures return an error; they are not confirmation that the DID is missing.

## Straight to the point

```text theme={null}
Prepare: POST /dids/{url-encoded-did}/prepare
Sign: Ed25519.sign(private_key, hex_decode(payload_to_sign))
Submit: returned request + Base64 signature to the action's public endpoint
```


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