{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://travel.agenthaven.dev/contracts/schemas/request-envelope.schema.json",
  "title": "Signed request envelope (payload of a request+jwt)",
  "description": "Every buyer call to the seller carries this envelope in the Authorization header (Bearer <compact JWS>), signed by the buyer's stable instance key: header {alg: ES256, typ: request+jwt, kid: <thumbprint of that key>}. The seller resolves the key from the buyer's published key attestation at https://<trust domain of iss>/.well-known/agent-keys.json (check 3), never from the token. Check 2 verifies, in this order and before any fetch: iat within 60 seconds, nonce of 16+ characters, aud equal to the seller's public base URL, method and path equal to the call's, body_sha256 equal to SHA-256 over the raw body bytes (R-07); then the attestation, the signature, and finally the replay cache, per signer. The mandate travels beside it, in the body, as mandate_jws. A correlation_id in the envelope is the transaction's; a body naming a different one is refused. Over MCP the body is the whole JSON-RPC message. Status: IMPLEMENTED by the seller (check 2, since 2026-09-07) and by agent-buyer (envelope.py), signing from https://buyer.onbehalf.dev since 2026-09-09; cross-implementation vector agent-buyer/vectors/checkout-envelope.json. Since 2026-09-19 the same envelope, with aud the authority's issuer, method POST and path /mandate-requests, is what the mandate authority reads on a mandate request (authority-api.md, Who may ask); agent-buyer signs it when AGENT_BUYER_SIGN_AUTHORITY_REQUESTS is on.",
  "type": "object",
  "required": ["iss", "aud", "iat", "nonce", "correlation_id", "method", "path", "body_sha256"],
  "properties": {
    "iss": { "type": "string", "pattern": "^spiffe://", "description": "The buyer instance's SPIFFE ID." },
    "aud": { "type": "string", "format": "uri", "description": "The resource the call is addressed to: the seller's public base URL, or the mandate authority's issuer." },
    "iat": { "type": "integer", "description": "Seconds. Accepted within 60 seconds either way; nonces are kept for the window plus skew (120 seconds)." },
    "nonce": { "type": "string", "minLength": 16, "description": "Unique per request. Replay is refused with nonce_replayed." },
    "correlation_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "Minted by the buyer at intent.captured, one per transaction, the same in every call of it." },
    "method": { "type": "string", "enum": ["POST"] },
    "path": { "type": "string", "description": "The request path, e.g. /a2a or /mcp." },
    "body_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "SHA-256 over the raw request body bytes. A body edited after signing fails here (R-07, signature_invalid)." },
    "attestation_url": { "type": "string", "format": "uri", "description": "Where the seller fetches the buyer's key attestation (/.well-known/agent-keys.json on the buyer's domain). Optional: the seller may derive it from the SPIFFE ID's trust domain." }
  }
}
