B4. REST binding
Status: normative. Binds the A8 recipient API to HTTP. Document version 1.0-draft-1.
B4.1 Contract and routes
The complete recipient contract is OpenAPI 3.1, generated from the same schema definitions as MCP. The file uses JSON syntax, which is valid YAML. This is a draft contract, not a deployed endpoint. Public discovery is unauthenticated; every recipient action is authenticated and authorised.
Use HTTPS, exact <origin>/v1 audience, and Autonym-Version:1.0 on protocol responses. Every access token is DPoP-bound (A6.3): a request carries Authorization:DPoP plus the DPoP header, and a token presented as Bearer is refused. Reject repeated scalar query parameters, malformed values, unknown fields and unknown protocol versions with invalid_request. Comma-separated domain/key lists have no empty items or duplicates. Maximum body size is 64 KiB, including nested values; a larger body fails payload_too_large. A context response has at most 1,000 entries; reject an over-limit request without a partial unmarked disclosure.
| Method | Path | Result |
|---|---|---|
| GET | /.well-known/autonym |
Provider discovery |
| GET | /v1/grant |
Current authenticated grant |
| GET | /v1/domains |
Eligible granted domains/keys, without counts |
| GET | /v1/context |
Signed disclosure, one counted read |
| GET | /v1/context/{domain} |
Same, with conditional-request support |
| POST | /v1/proposals |
Contribution event acknowledgement |
| GET | /v1/proposals/{id} |
Own proposal status only |
| POST | /v1/proposals/{id}/confirm |
Exact-statement confirmation/review |
| DELETE | /v1/proposals/{id} |
Withdraw own proposal |
| GET | /v1/purge-instructions |
At most 100 outstanding signed instructions for this client |
| POST | /v1/purge-instructions/{jti}/ack |
Purge acknowledgement |
The path ID and body ID must match wherever both occur. Mutating requests other than contribution events require a client-scoped UUIDv4 Idempotency-Key, canonical-payload equality, and 30-day deduplication. A reused key with a different payload fails idempotency_conflict.
B4.2 Conditional reads
An ETag is a quoted opaque HMAC under a dedicated provider key of JCS containing the client, grant ID/revision, the A9 canonical request, sorted selected alias/version/level triples, temporal selection epoch and the previous envelope deadline. Store its association with that exact signed envelope and response hash. Never use a content-only ETag.
A matching If-None-Match may return 304 only while the prior envelope is still valid, its entire selection and authority still match, and the grant has not exhausted its read limit. This writes a read_not_modified event and counts towards rate limits but does not increment reads_used. It cannot extend a signed deadline. At or after any time boundary return a new counted signed response if permitted, or the relevant error. Revocation, counter checks and dependency checks cannot be bypassed through 304. Responses use Cache-Control:no-store; this conditional facility is only for a recipient's explicitly held, still-valid transient object.
B4.3 Errors and limits
errors.json is the closed registry, and problem.json is the exact RFC 9457 representation. Each registered code has one urn:autonym:error:<code> type, one status and one title, and names the sections whose text raises it; a response carries exactly that status. No rejected value, record content, credential or existence hint appears in an error. Authentication/token-endpoint errors retain their OAuth-defined representation, and a 401 also carries the A6.1 WWW-Authenticate challenge. The registry separately lists the OAuth codes this specification cites and the codes the B1 grant binding takes from its base specification (B1.9); they keep the representation their own specifications define and are not registered codes. handle_moved is deliberately removed; API migration does not redirect credentials or disclose a destination.
An unknown path answers not_found. An unexpected failure answers internal_error, and a provider that cannot reach its key storage or grant state answers not_ready (A15.3); neither says why.
The provider enforces at least per-client and per-grant rate limits and answers 429 rate_limited with Retry-After. Default ceiling is 60 authorised requests per minute per grant and 600 per minute per client; a provider may lower these published operational limits, but cannot silently increase consent limits.
Checks: TRANSPORT-01, WIRE-01, TEMP-03, CORE-01, LOG-01, PURGE-01, MIGRATE-01.
References to other standards and projects describe intended technical alignment only and do not imply endorsement or partnership.