Skip to main content
Read-only requests do not require your private key. Updates do, because a Directory must distinguish the DID controller from somebody merely claiming to be the controller. Authorization happens entirely on your device:
  1. Read the current nonce.
  2. Build the operation’s canonical payload.
  3. Sign the exact payload bytes with an authorized Ed25519 key.
  4. Send the public fields, encoded payload, and signature.
The Directory receives no private key.

Nonces prevent replay

A nonce is a counter associated with a DID authorization domain. Once a nonce is used successfully, another request cannot reuse it. Fetch current values with:
Use the nonce named for the operation you are building. If another update is submitted first, fetch the values again and rebuild the signature. Existing Persona operations have separate counters. Fetch them with:
The nonce route returns 404 before initial registration. For registration, use the challenge_nonce and operator_nonce returned by the DNS-challenge response. For an existing Persona, use persona_nonce for DNS challenge and attestation replay protection, operator_nonce for signed Persona registration-state operations, and policy_nonce for that Persona’s policy and delivery constraints. operator_nonce belongs to the operator DID rather than one Persona, so another Persona operation under the same operator can make it stale. A Persona transfer challenge binds both the current persona_nonce and the current operator’s operator_nonce.

Expiration limits stolen requests

valid_until is an unsigned 64-bit Unix timestamp in milliseconds for SCALE authorization payloads. Use a short future window and make sure the machine signing the request has an accurate clock.

Canonical payloads are bytes

For each signed chain-state mutation that carries a proof, canonical_payload is the exact SCALE-encoded authorization structure. DNS challenge creation and verification prepare these operations but do not themselves carry a caller signature. Send a canonical payload as:
  • Hex beginning with 0x, or
  • Standard or URL-safe Base64
The Directory decodes the value, reconstructs the expected structure from the other request fields, and compares the bytes. Signing a JSON object or a visually similar string will not work. The document authorization field order is: Each endpoint page identifies which optional item is populated. Alias payloads use this field order: Root-public-key rotation uses a distinct payload: Device and deactivation payloads use: The operation schema identifies add, tombstone, update, and remove device actions and DID deactivation. Use the schema version returned by the Directory or current SDK; do not reuse the removed policy-link action encoding. Delivery-policy payloads bind the complete replacement or deletion to its scope: The operation value carries the canonical DID or Persona scope and the complete policy or requested constraints where applicable. The current Policy V2 actions set or delete one DID- or Persona-scoped policy or update DID or Persona delivery constraints. Tag-scoped actions have been removed; a tag is a rule condition. A Persona registration payload binds the canonical DNS name, action, proposed controller set and threshold, optional delivery constraints, DNS validation attestation, challenge nonce, operator nonce, and valid_until. Renewal binds the same fields except a replacement controller set: it preserves the finalized controllers, which can change only through the rotation endpoint. Persona v1 requires controller_threshold: 1. Initial registration is signed by one proposed controller that is already a signing key on the operator DID; renewal is signed by one active Persona controller. A Persona transfer has two nested authorization layers. The new operator signs the Directory-returned acceptance_payload with a proposed new controller. The Directory then binds that signature and the DNS attestation into canonical_payload, which an active current Persona controller signs. The chain verifies both signatures and the attestation before replacing the operator and controller set. Use the returned bytes exactly; neither payload is JSON.
The Directory submits only DID-key proof calls. Account-owner pallet calls remain available to developers who interact with the chain directly, but they are not Directory HTTP endpoints.

Sign the bytes, not their printed encoding

If canonical_payload is Base64, decode it and sign the decoded bytes. Do not sign the Base64 characters. The resulting Ed25519 signature is sent as Base64 in signature.

Signer selection

Set signer_key_id to:
  • root to use the record’s root public key, or
  • A complete authorized verification-method ID such as did:openpayload:...#signing
The key must already be authorized by the DID record.

Why the body repeats the DID and action

The path selects the resource. The signed body binds the authorization to the same DID and one exact operation. The Directory rejects a mismatch rather than guessing what the caller intended.

Straight to the point

Never send private_key, a mnemonic, or a seed phrase.