The wire format
The X-MotherShy header carries a compact, single-line JSON envelope. This page is the authoritative schema.
The envelope
json
{
"cert": { "path": "agents/alice", "pub": "<b64>", "sig": "<b64>" },
"req": { "agent": "<b64>", "site": "example.com", "nonce": 12345,
"ts": 1728000000, "amt_microusd": 5, "window": 300 },
"sig": "<b64>",
"cap": { "v": 1, "id": "cap-1", "holder": "<b64>", "aud": "example.com",
"actions": ["retrieval"], "cap_microusd": 1000,
"issued_at": 1728000000, "expires_at": 1728003600,
"policy_receipt": "receipt-1", "verification_mode": "offline",
"sig": "<b64>" }
}Field reference
cert — the birth certificate
| Field | Type | Meaning |
|---|---|---|
path | string | Derivation path (e.g. agents/alice) |
pub | base64 (32B) | Agent public key |
sig | base64 | Mother's signature over "birth:" + path + ":" + pub |
req — the request
| Field | Type | Meaning |
|---|---|---|
agent | base64 | Agent public key — must equal cert.pub |
site | string | Target site (the audience) |
nonce | int | Anti-replay nonce (JS safe integer) |
ts | int | Unix seconds |
amt_microusd | int | Amount authorized (≤ budget) |
window | int | Hour bucket |
sig — the request signature
Agent's Ed25519 signature over the canonical request serialization.
cap — the capability (optional, but required to pass)
| Field | Type | Meaning |
|---|---|---|
v | int | Version (must be 1) |
id | string | Capability id |
holder | base64 | Agent public key — must match cert.pub |
aud | string | Audience — must match req.site |
actions | string[] | ["retrieval"] only today |
cap_microusd | int | Spend budget |
issued_at | int | Mint time |
expires_at | int | Expiry (mandatory for offline) |
policy_receipt | string | Policy receipt id |
verification_mode | string | offline | online |
sig | base64 | Mother's signature over the canonical capability |
The canonical byte layouts
Signatures are over fixed-order serializations — reproduce them exactly, never re-order:
text
cert signing bytes = "birth:" + path + ":" + rawPub(32 bytes)
request canonical = {"agent":<b64>,"site":<str>,"nonce":<int>,"ts":<int>,
"amt_microusd":<int>,"window":<int>}
capability canonical = {"v":1,"id":<str>,"holder":<b64>,"aud":<str>,
"actions":["retrieval"],"cap_microusd":<int>,
"issued_at":<int>,"expires_at":<int>,
"policy_receipt":<str>,"verification_mode":<str>}All amounts are integer micro-USD. All signatures are pure RFC 8032 Ed25519.
Don't JSON.stringify blindly
JavaScript object key order can differ from the canonical order. Always serialize fields in the fixed order above, or your signature won't verify.
Audience normalization
site / aud are normalized to a canonical hostname: lowercased, IDNA/punycode, scheme/path/query/port stripped, trailing dot removed. https://Example.com/path → example.com.