Skip to main content
A DDN envelope is the package an OpenPayload client sends through Relay and Cache nodes. Think of it as an addressed, sealed parcel:
  • The outer fields tell nodes where and how to handle it.
  • The encrypted header carries protected routing or application metadata.
  • The payload carries encrypted message data.
Nodes validate the outer shape but do not need to decrypt your message.

Smallest practical shape

Required fields

An encrypted header is strongly recommended for real data, but it is not required by the transport envelope. If using flat fields, supply encrypted_header, header_nonce, schema_version, and either header_key_id or header_key_epoch.

Common optional fields

Unknown outer fields are rejected. This protects interoperability by preventing different clients from silently inventing incompatible headers.

Network-managed policy provenance

An original sender should omit expires_at and must not submit policy_context, policy_id, policy_revision, policy_rule_id, policy_block_hash, or policy_block_number. These are reserved network fields, not client authorization inputs. The public Relay routes reject client-supplied policy provenance with 400 client_policy_context_forbidden. The winning rule comes from finalized state and remains fixed for the delivery attempt. Network-managed provenance is not part of the compatible-client envelope contract, and copied client fields never grant policy authority. When no rule applies, the Relay uses ordinary DID services. A lookup failure is not equivalent to policy-free fall-through.

Recipient, Persona, and tag

The target syntax is:
Examples:
@persona is optional. A Persona is a registered policy name. Domain-shaped Persona names require DNS verification; simple names do not. An alias cannot contain @ or #, so the separator is unambiguous. Resolution does not rewrite the flat to value. When the envelope carries a sender signature, that signature continues to bind the exact DID-or-alias selector the sender supplied.

Persona release profile

For a recipient whose Persona policy requires gated delivery, first call delivery resolution with the complete recipientDid@persona target. The Directory returns the recipient’s DID document, the selected policy, and the public recipient and processor keys. Seal the payload with the returned openpayload:persona-release:v1 profile, sign the envelope, and send that same envelope to the Relay. The Relay checks its public shape and policy binding before following the delivery plan. The recipient must verify a processor unlock before opening the payload. The gated envelope must include a sender DID and a valid sender signature. Its payload is a JSON object with profile, id matching message_id, recipient_did, persona, selected policy_id and policy_revision, recipient_key_id, processor_key_id, Base64 nonce and ciphertext, and recipient_package and processor_package objects. Each package has Base64 enc and ct values. The Relay checks that the nonce decodes to 12 bytes, both enc values decode to 32 bytes, and the ciphertext fields meet the profile’s size bounds. It does not decrypt or validate the cryptographic construction. The network does not inspect the plaintext or prove that the client applied the profile correctly. Applications still choose their own content format inside the encrypted payload. Do not append #tag to to. Keep the optional tag in the top-level tag field. Tags, labels, and categories are synonymous policy concepts, but tag is the only envelope field. Tags are public, nonblank, case-sensitive, and operator-defined, with a maximum of 96 UTF-8 bytes; they cannot contain control characters or NUL. Leading and trailing spaces are preserved rather than stripped. Do not place secret classifications or plaintext message content in a tag. Policy resolution uses finalized chain state and includes an optional Persona and tag as selectors. Relay and Cache nodes may reuse a resolved policy for its policy_ttl_seconds. This ensures DID policies still apply without either selector. A Persona rule has precedence over a DID rule. If no rule applies, delivery falls through to the recipient DID’s ordinary services. application_id identifies a separate application control policy. It does not select the recipient delivery route or change message retention. A sender signature that includes application_id binds that identifier to the message. The V3 policy format lets an applicable Application rule react to a Cache store or local Relay delivery with a templated Send or Call step. The application must verify any proof it places in context; the network does not interpret it.

TTL and size limits

ttl is the message’s requested retention duration. It is not the scope operator’s chain setting. The DID or Persona publishes requested_cache_seconds, and the chain derives effective_ttl_seconds no greater than 48 hours. The Relay applies the lesser of the envelope request and the chain-derived effective TTL, then produces one absolute expires_at timestamp for every Cache replica. The network rejects an envelope outside these ceilings: A DID, Persona, or matching policy rule can publish lower delivery constraints. The 64 KiB non-payload metadata ceiling is fixed by the network and has no operator constraint field. For larger files, use out-of-band object storage and send an encrypted reference in the payload.

Chunked messages

For a large encrypted object, send independently deliverable chunks. Each chunk has its own message_id and shares a UUID message_group_id.
sequence_number begins at 0 and must be less than total_chunks. Relay and Cache nodes do not reassemble or decrypt the content. Each decoded chunk is at most 2 MiB. OpenPayload does not define a network-wide maximum chunk count or aggregate message size. A Relay can still reject an individual envelope with 413 or reject assured staging with 429/507 when its advertised size or operational capacity is exceeded. Supplying message_group_id, sequence_number, and total_chunks opts into assured chunk submission. The Relay durably stages the opaque envelopes, without decrypting or reassembling them, until every declared sequence is present. An identical chunk may be retried. A different envelope that reuses an occupied sequence is rejected with 409. A 202 chunk_staged response means the set is still incomplete; 202 chunk_set_delivered means the Relay completed delivery of the declared set. If the set remains incomplete past the Relay’s staging window, it is purged.

Sender signatures

Sender identity is optional at the envelope-validation layer. If you provide either the sender DID or signature, provide both. Nodes that verify the sender resolve the DID and check the signature against its authorized public key. When application_id is present, the signed envelope uses the openpayload:ddn-envelope:v2 canonical form and includes that exact identifier. Envelopes without application_id retain the v1 form.

Straight to the point

  • JSON object only
  • UUID message_id
  • Valid recipient DID or alias with an optional @persona suffix
  • Timestamp plus payload
  • Optional top-level tag; never put a tag in to
  • Optional top-level application_id, independent of tag
  • Optional flat encrypted header or client-defined context; a non-null context must be a JSON object
  • No unknown top-level fields
  • Maximum effective retention: 48 hours; a longer request is clamped
  • Encrypt before sending