curl --request POST \
--url "https://relay.example.com/relay" \
--header "Content-Type: application/json" \
--data '{
"message_id": "9f8d6f08-bce5-4df5-b22b-bf8c6bd4e143",
"to": "did:openpayload:1111111111111111111111@example.com",
"tag": "Legal",
"timestamp": "<current-RFC3339-timestamp>",
"ttl": "24h",
"delivery_hint": "standard",
"payload": {
"ciphertext_b64": "<encrypted-message>"
},
"encrypted_header": "<base64-encrypted-header>",
"header_nonce": "<base64-nonce>",
"header_key_id": "recipient-key-1",
"schema_version": "1"
}'
{
"success": true,
"delivery_mode": "policy_delivery",
"http_status": 202,
"code": "policy_applied",
"message": "Winning delivery policy completed.",
"retry_count": 2,
"cache_attempted": true,
"cache_result": "accepted",
"details": {
"policy_id": "0x<64-hex-policy-id>",
"policy_revision": 4,
"rule_id": "legal-delivery",
"policy_source": "persona",
"block_hash": "0x<finalized-block-hash>",
"forwarded_endpoints": [
"https://inspection.example.com"
],
"accepted_caches": [
"https://cache.example.com",
"https://cache-2.example.com"
],
"accepted_archives": []
}
}
Relay API
Send an encrypted message
Submit a DDN envelope to a Relay using the recipient declared in the envelope
curl --request POST \
--url "https://relay.example.com/relay" \
--header "Content-Type: application/json" \
--data '{
"message_id": "9f8d6f08-bce5-4df5-b22b-bf8c6bd4e143",
"to": "did:openpayload:1111111111111111111111@example.com",
"tag": "Legal",
"timestamp": "<current-RFC3339-timestamp>",
"ttl": "24h",
"delivery_hint": "standard",
"payload": {
"ciphertext_b64": "<encrypted-message>"
},
"encrypted_header": "<base64-encrypted-header>",
"header_nonce": "<base64-nonce>",
"header_key_id": "recipient-key-1",
"schema_version": "1"
}'
{
"success": true,
"delivery_mode": "policy_delivery",
"http_status": 202,
"code": "policy_applied",
"message": "Winning delivery policy completed.",
"retry_count": 2,
"cache_attempted": true,
"cache_result": "accepted",
"details": {
"policy_id": "0x<64-hex-policy-id>",
"policy_revision": 4,
"rule_id": "legal-delivery",
"policy_source": "persona",
"block_hash": "0x<finalized-block-hash>",
"forwarded_endpoints": [
"https://inspection.example.com"
],
"accepted_caches": [
"https://cache.example.com",
"https://cache-2.example.com"
],
"accepted_archives": []
}
}
Use this endpoint after your client has resolved the recipient, encrypted the message, and built a DDN envelope. The Relay reads only the public outer fields needed for validation and delivery.
Do not send
For policy delivery,
policy_context, policy_id, policy_revision, policy_rule_id, policy_block_hash, or policy_block_number. These fields are reserved network provenance, and this route rejects them with 400 client_policy_context_forbidden.
Request
The body is one JSON DDN envelope.string
required
A UUID generated once for this message. Reusing it may cause deduplication.
string
required
The recipient DID or alias, optionally followed by
@persona. recipient is accepted as an alternate field name. Do not append a tag.string
Optional public, case-sensitive message classification used by policy conditions.
string
Optional registered application identifier. It is separate from
tag and does not change recipient delivery routing. If the sender signs the envelope, include it in the v2 canonical signature payload.string
required
ISO-8601, epoch milliseconds, or epoch seconds.
created_at is accepted as an alternate.object
required
Your encrypted application payload.
string
Base64 encrypted header. When used, also send
header_nonce, schema_version, and a header key reference.object | null
Optional client-defined JSON context. A client may set this field to
null or omit it. When non-null, it must be a JSON object, but Relay does not interpret or impose an application schema on its contents.string
UUID shared by an assured chunk set. When present, also send
sequence_number and total_chunks.integer
Zero-based position in the assured chunk set. An identical sequence may be retried; conflicting content is rejected.
integer
Number of envelopes the sender commits to submit for this set. Every envelope in the set must declare the same value.
curl --request POST \
--url "https://relay.example.com/relay" \
--header "Content-Type: application/json" \
--data '{
"message_id": "9f8d6f08-bce5-4df5-b22b-bf8c6bd4e143",
"to": "did:openpayload:1111111111111111111111@example.com",
"tag": "Legal",
"timestamp": "<current-RFC3339-timestamp>",
"ttl": "24h",
"delivery_hint": "standard",
"payload": {
"ciphertext_b64": "<encrypted-message>"
},
"encrypted_header": "<base64-encrypted-header>",
"header_nonce": "<base64-nonce>",
"header_key_id": "recipient-key-1",
"schema_version": "1"
}'
Response
boolean
required
Whether the Relay completed the reported delivery mode.
string
required
The successful mode or
failed. policy_handoff means another Relay accepted responsibility for the remaining plan; it does not confirm later Store or Archive completion.integer
required
The HTTP status represented by the result.
string
required
A stable machine-readable result code.
string
required
Human-readable result summary. Branch on
code, not this text.integer
required
Downstream delivery attempts represented by this response, including the first attempt. The field name is retained for compatibility.
boolean
required
Whether the Relay made an actual Cache HTTP attempt, including for a policy
Store step. This remains true when every attempted Cache rejects or fails.string | null
Cache outcome when applicable. Common values are
accepted, attempted, failed, and no_cache_endpoints; a failed base-DID Cache request can instead expose that Cache’s textual response. Treat this as diagnostic text and branch on code instead.object
required
Policy provenance and endpoints used by policy execution.
accepted_caches and accepted_archives distinguish observed Store and Archive accepts. Base-DID direct delivery can return an empty object; base Cache fallback can return accepted_caches and attempted_caches.{
"success": true,
"delivery_mode": "policy_delivery",
"http_status": 202,
"code": "policy_applied",
"message": "Winning delivery policy completed.",
"retry_count": 2,
"cache_attempted": true,
"cache_result": "accepted",
"details": {
"policy_id": "0x<64-hex-policy-id>",
"policy_revision": 4,
"rule_id": "legal-delivery",
"policy_source": "persona",
"block_hash": "0x<finalized-block-hash>",
"forwarded_endpoints": [
"https://inspection.example.com"
],
"accepted_caches": [
"https://cache.example.com",
"https://cache-2.example.com"
],
"accepted_archives": []
}
}
details.accepted_caches contains Store endpoints observed by the responding Relay, and details.accepted_archives contains Archive endpoints. Neither array aggregates storage accepted later after a Forward step.
For assured chunk submission, 202 chunk_staged means the Relay durably accepted this envelope and is waiting for the remaining declared sequences. 202 chunk_set_delivered means the complete set was delivered. Staging and completed-sequence progress survive a normal Relay process restart. If delivery is interrupted, retry an identical outstanding chunk before details.retry_until; the Relay resumes with the undelivered sequences. The Relay purges a set that remains incomplete past that time.
Common failures
| Status | Meaning |
|---|---|
400 | Invalid JSON, missing field, unknown field, malformed DID, UUID, TTL, header or chunk metadata, or client-supplied policy transport metadata |
403 | A supplied sender signature or delivery-policy authorization check failed, or the winning action is Reject/v1 |
404 | Recipient or required public service information was not found |
409 | A chunk set changed total_chunks, or a sequence was reused with different content |
413 | Envelope, header, payload, or chunk exceeds the node’s advertised limit |
422 | Message, Persona, constraint, or winning delivery plan is not deliverable |
429 | Relay is rate-limiting requests or its assured-staging capacity is full |
502/503 | An upstream destination or required service is unavailable |
507 | The Relay could not durably persist assured staging state |
Straight to the point
POST /relay
Content-Type: application/json
<DDN envelope whose to field is did-or-alias[@persona]>
- Keep
tagin its top-level field - Omit
policy_contextand allpolicy_*fields - No matching policy falls through to ordinary DID services
- A failed policy lookup does not fall through

