Federation
StableGenerated from capsule-server/openapi.json, the OpenAPI 3.2 document
capsule-server emits and mise run openapi-check-kynos keeps current. To change a
description on this page, change the annotation on the handler or model it comes from
and regenerate — this file is build output. The auth model, error contract, and
conventions common to every endpoint are on the REST API overview.
POST /v1/federation/capabilities/refresh
Section titled “POST /v1/federation/capabilities/refresh”Exchange a capability for its successor.
The credential is the capability being refreshed; a session token has nothing to refresh here and is refused.
Answers 404 error.federation.not_configured when this deployment does not federate —
FEDERATION_ENABLED is off, which is the default — before the credential is verified, a
budget is charged or a store is touched.
Authentication: required — bearer.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Request-Signature | header | string | null | t=<Unix seconds>, n=<nonce>, s=<base64url Ed25519 signature>, made by the peer a presented federation capability names, over the request’s method, path and capability (design/federation.md, “Request Signatures”). Required with a capability; ignored with a session token. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
| Status | Body | Description |
|---|---|---|
200 | RefreshedCapabilityResponse application/json | OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Forbidden; Capability invalid; Capability revoked; Server blocked; Capability expired. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
409 | CodedProblem application/problem+json | Member not on roster. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
425 | CodedProblem application/problem+json | Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
426 | CodedProblem application/problem+json | Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
429 | CodedProblem application/problem+json | Rate budget exceeded. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
POST /v1/federation/hints
Section titled “POST /v1/federation/hints”Receive a signed pull hint from an album’s home server.
Answers 404 error.federation.not_configured when this deployment does not federate —
FEDERATION_ENABLED is off, which is the default — before the body is read, a budget is
charged or a store is touched.
A hint is advisory, and that is all it is
Section titled “A hint is advisory, and that is all it is”A verified hint brings the job pulling album_id from home_server forward: no sooner than
one minute after that job’s last pull, never for a peer on probation, and never past the
job’s back-off after a failed pull or the peer’s open circuit, which the pull worker applies
to the job exactly as it would have. A hint adds no job, changes nothing about what is pulled or where from, and carries
nothing that reaches validation. The album is pulled on its own interval whether or not a
hint ever arrives, so a refused hint costs at most that interval.
Only a pinned peer can hint, and only about its own albums
Section titled “Only a pinned peer can hint, and only about its own albums”The hint carries its own Ed25519 signature, verified against the key an operator pinned for
home_server with capsule-server peer pin; a peer nobody pinned is
403 error.federation.peer_unknown, whatever it signed. The job a hint touches is keyed on the
signer, so a peer can only hint about albums this server pulls from that peer.
The order the checks run in
Section titled “The order the checks run in”The order report intake runs them in: bounds; whether it is addressed here and signed just
now; who is speaking; whether they are welcome; whether they really said it; whether they said
it before; how much they may ask for. No budget is charged before the signature
verifies, so a stranger cannot spend a real peer’s hint budget by sending garbage under its
name. A hint addressed to another server, signed more than five minutes from this server’s
clock, or reusing a nonce this peer already used is 401 error.federation.hint_unsigned; a
peer that retries signs again with a fresh nonce.
202 whether or not this server pulls the album
Section titled “202 whether or not this server pulls the album”A verified, admitted hint is answered 202 with the instant it was received, whatever became
of it: it moved a job, the job was already due, this server pulls no such album, or the
peer is on probation. Telling them apart would let a pinned peer walk album ids and read off
which ones this server’s members subscribe to. A held job and one that is not cost the same
work — one peer read and one schedule operation — so the answer’s timing does not tell them
apart either; a peer on probation is answered after the peer read alone, which tells it only
its own standing.
Only a store that could not answer is different: 500 error.federation.unavailable, which
says nothing about any album.
Authentication: none.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
Request body (required, application/json): PullHintRequest
| Status | Body | Description |
|---|---|---|
202 | PullHintResponse application/json | The hint was received. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed hint; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Hint unsigned. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Peer unknown; Server blocked. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | Payload Too Large; the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
415 | CodedProblem application/problem+json | Unsupported Media Type. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
422 | CodedProblem application/problem+json | Unprocessable Entity. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
425 | CodedProblem application/problem+json | Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
426 | CodedProblem application/problem+json | Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
429 | CodedProblem application/problem+json | Hint rate limited. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
POST /v1/federation/reports
Section titled “POST /v1/federation/reports”File a signed moderation report from a peer server.
Answers 404 error.federation.not_configured when this deployment does not federate —
FEDERATION_ENABLED is off, which is the default — before the body is read, a budget is
charged or a store is touched.
Only a pinned peer can file
Section titled “Only a pinned peer can file”A report is verified against the peer’s operator-pinned key, which an operator writes
with capsule-server peer pin. A peer nobody pinned is answered
403 error.federation.peer_unknown, whatever it signed.
No bearer, and why that is not “unauthenticated”
Section titled “No bearer, and why that is not “unauthenticated””The reporting peer holds no capability here — it is reporting this server’s content, not
pulling it — so there is nothing to present. What it does hold is a key an operator has
pinned, and the report carries its own Ed25519 signature over the canonical CBOR of every
other field. A report from a server nobody has pinned is 403: intake is not the moment a
peer becomes trusted (design/federation.md’s TOFU is explicitly not done here).
The order the checks run in
Section titled “The order the checks run in”Bounds, then whether it is addressed here and signed just now, then who is speaking, then whether they are welcome, then whether they really said it, then whether they said it before, then how much they may ask for at all, then whose account it is, then whether they have said it too often.
Every field is length-capped first, and reporting_server must be a host name, before a store
is read or a byte is keyed on. The recipient and the freshness window are pure checks on the
body. No budget is charged before the signature verifies (design/moderation.md): a budget
keyed on an origin a body merely claims is one a stranger spends in a real peer’s name. What an
anonymous caller gets before that is one peer-store read and one Ed25519 verification — the
work every bearer check costs on any authenticated route.
Once verified: the nonce is checked (a replay is refused before anything is charged to the
peer), then [CounterKey::FederatedIntake] bounds the peer’s total intake, then the nonce is
spent. Then the policy budgets: the contract’s per-(server, account) limit, and a
per-peer ceiling that ignores the account, because reported_user is a string the peer
chooses and a peer cycling accounts would otherwise mint itself a fresh allowance each time.
A signed report is accepted once, here, now
Section titled “A signed report is accepted once, here, now”The claim names its recipient and carries a nonce and the instant it was signed; a report
addressed to another server, signed more than
REPORT_FRESHNESS from this server’s clock, or
carrying a nonce this peer already used is 401 error.moderation.report_unsigned. A peer that
retries — after a 429, a timeout, a 500 — signs again with a fresh nonce.
Before any of that, the bytes parsed are bounded too: the federation group’s body cap,
MAX_FEDERATION_BODY_BYTES, refuses a body past
16 KiB with 413 before it is read — far above any real report, far below the upload
backstop every other group carries.
What accepting one does
Section titled “What accepting one does”It writes a row an operator will read (ModerationStore::pending_reports) and nothing
else. A peer’s report is an input to a decision, never a decision: no standing changes, no
serving hold appears, and the reported account sees nothing — because nothing has been done
to them.
202 whether or not the account exists
Section titled “202 whether or not the account exists”A report naming an account this server does not host is accepted on the wire and dropped,
with a warn for the operator. It is not filed: an unresolvable report is a permanent orphan
row that nobody can act on, which is the reason the check exists at all.
The answer is deliberately the same one a filed report gets. An earlier version refused with a
distinct coded 404, and that manufactured an account-enumeration oracle out of a check that
did not need one: a pinned peer could walk identifiers and read existence off the status line.
“Pinned” is not “trusted with enumeration” — a peer key can be compromised, and a peer can be
adversarial toward its own users while remaining an operator’s legitimate partner — and this
codebase treats exists-versus-does-not as a first-order defect nearly everywhere else
([crate::routes::enroll]‘s indistinguishable code refusal, the album ceremonies’ “not yours
is not found”, [crate::serve::authority]‘s 404/403 boundary).
Probing is not free even so: every budget above is charged before this point is reached, so a
peer sweeping identifiers spends its allowance doing it and an operator sees the warn.
Authentication: none.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
Request body (required, application/json): FederatedReportRequest
| Status | Body | Description |
|---|---|---|
202 | FederatedReportResponse application/json | The report was accepted for review. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed report; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Report unsigned. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Peer unknown; Server blocked. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | Payload Too Large; the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
415 | CodedProblem application/problem+json | Unsupported Media Type. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
422 | CodedProblem application/problem+json | Unprocessable Entity. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
425 | CodedProblem application/problem+json | Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
426 | CodedProblem application/problem+json | Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
429 | CodedProblem application/problem+json | Report rate limited. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
GET /v1/federation/subscriptions
Section titled “GET /v1/federation/subscriptions”List the caller’s subscriptions to federated albums, live or lapsed.
Answers 404 error.federation.not_configured when this deployment does not federate.
Authentication: required — bearer.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
| Status | Body | Description |
|---|---|---|
200 | SubscriptionsResponse application/json | OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
POST /v1/federation/subscriptions
Section titled “POST /v1/federation/subscriptions”Subscribe to a federated album with the capability its home server minted for this server.
The capability is verified against the issuer’s pinned key before anything is recorded, and
must name this server as its recipient. Posting one for an album already subscribed keeps
whichever capability lives longer, so a replayed invite never undoes a renewal. An account
holds at most 1,000 subscriptions; one more is refused 403 error.federation.subscription_limit until the caller unsubscribes from another.
Answers 404 error.federation.not_configured when this deployment does not federate —
FEDERATION_ENABLED is off, which is the default — before the credential is read or a store
is touched.
Authentication: required — bearer.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
Request body (required, application/json): SubscribeRequest
| Status | Body | Description |
|---|---|---|
200 | SubscriptionView application/json | The caller already held this subscription; here it is as it now stands. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
201 | SubscriptionView application/json | The subscription was recorded. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | Payload Too Large; the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
415 | CodedProblem application/problem+json | Unsupported Media Type. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
422 | CodedProblem application/problem+json | Unprocessable Entity. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
425 | CodedProblem application/problem+json | Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
426 | CodedProblem application/problem+json | Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
DELETE /v1/federation/subscriptions/{peer}/{album_id}
Section titled “DELETE /v1/federation/subscriptions/{peer}/{album_id}”Stop pulling one federated album for the caller.
Idempotent: a subscription the caller does not hold is the same 204. Another member’s
subscription to the same album is untouched, and so is anything already pulled.
Answers 404 error.federation.not_configured when this deployment does not federate.
Authentication: required — bearer.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
album_id | path | string | Required. The album, as its home server names it. |
peer | path | string | Required. The album’s home server. |
| Status | Body | Description |
|---|---|---|
204 | — | the request succeeded and there is no content to send. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
425 | CodedProblem application/problem+json | Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
426 | CodedProblem application/problem+json | Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
GET /v1/federation/subscriptions/{peer}/{album_id}/assets
Section titled “GET /v1/federation/subscriptions/{peer}/{album_id}/assets”List the assets this server pulled for one of the caller’s subscriptions, a page at a time.
Each asset is its breadcrumb, read from the latest entry a pull accepted for it, so nothing listed is anything but what passed this server’s re-validation. Deleted and purged assets are not listed. A subscription nothing has been pulled for yet answers an empty page.
Answers 404 error.federation.album_not_found when the caller holds no live subscription to
the album, whoever else does; and 404 error.federation.not_configured when
this deployment does not federate.
Authentication: required — bearer.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
album_id | path | string | Required. The album, as its home server names it. |
peer | path | string | Required. The album’s home server. |
after | query | string | null | Resume after this asset id: the next_after the previous page answered. Absent starts from the first asset. |
limit | query | integer | null | How many assets to answer: 100 when absent, and clamped into 1 to 1,000. |
| Status | Body | Description |
|---|---|---|
200 | PulledAssetsResponse application/json | OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
GET /v1/federation/subscriptions/{peer}/{album_id}/assets/{asset_id}/metadata
Section titled “GET /v1/federation/subscriptions/{peer}/{album_id}/assets/{asset_id}/metadata”Fetch the encrypted metadata blob one asset of a pulled album carries, as the pull stored it.
Opaque octets, byte for byte what the album’s home server served and this server verified against its address: this server holds no key to them. The blob is the one the asset’s latest accepted entry carries.
Answers 404 error.federation.album_not_found when the caller holds no live subscription to
the album, or the album holds no live asset by that id with a metadata blob; and 404 error.federation.not_configured when this deployment does not federate.
Authentication: required — bearer.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Crypto-Suite | header | integer | The crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400. |
X-Capsule-Protocol | header | string | Required. The YYYY-MM-DD protocol version this request is written against. Outside the server’s [X-Capsule-Protocol-Min, X-Capsule-Protocol-Max] window the request is refused with 426. |
X-Capsule-Sidecar-Schema | header | integer | The sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400. |
album_id | path | string | Required. The album, as its home server names it. |
asset_id | path | string | Required. The asset, as its home server names it. |
peer | path | string | Required. The album’s home server. |
| Status | Body | Description |
|---|---|---|
200 | string application/octet-stream | OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
401 | CodedProblem application/problem+json | Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
404 | CodedProblem application/problem+json | Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | CodedProblem application/problem+json | the request body exceeds the configured limit. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
500 | CodedProblem application/problem+json | Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
Schemas
Section titled “Schemas”The models these endpoints carry. A field whose type names another model links to it when this page documents that model, which it does when some path from an operation reaches it within 4 references. A model only ever reached deeper than that is named without being expanded.
CodedProblem
Section titled “CodedProblem”An RFC 9457 problem detail.
| Field | Type | Description |
|---|---|---|
type | string | Required. |
title | string | — |
status | integer | Required. |
detail | string | — |
instance | string | — |
code | string | Required. The stable error.* catalog code. The client localizes this; detail stays English. Present on every problem this server renders. |
request_id | string | The UUIDv7 this server minted for the request, as the X-Request-Id header carries it. Quote it when reporting the failure: it names the request’s log lines. |
FederatedReportRequest
Section titled “FederatedReportRequest”A moderation report one peer server files against an account on this one.
Every field except signature is covered by the signature, in canonical CBOR — see
[ReportClaim].
| Field | Type | Description |
|---|---|---|
reporting_server | string | Required. The peer filing the report, as its own server-info names it. |
recipient_server | string | Required. The server the report is addressed to — this one, as its own server-info names it. |
nonce | string | Required. A value the peer never signs twice: 16 to 64 bytes, a UUID being the obvious choice. |
reported_user | string | Required. The account on this server the report is about. |
asset_hash | string | Required. The content address of the asset complained about. |
album_id | string | Required. The album it was pulled from. |
reason | string | null | A short reason, where the peer gives one. |
reported_at | string | Required. When the peer signed the report, RFC 3339. Refused when more than five minutes from this server’s clock either way. |
signature | string | Required. The peer’s Ed25519 signature over the canonical CBOR of the fields above, base64. |
FederatedReportResponse
Section titled “FederatedReportResponse”An accepted report.
The identifier is this server’s, so an operator and the reporting peer can talk about one report. Nothing about the reported account is echoed — accepting a report says nothing about whether it is true, and a body that reported on the account’s standing would say it does.
| Field | Type | Description |
|---|---|---|
report_id | string | Required. This server’s identifier for the report. |
received_at | string | Required. When this server accepted it, RFC 3339. |
PullHintRequest
Section titled “PullHintRequest”An advisory hint from an album’s home server: “album A has news”.
Every field except signature is covered by the signature, in canonical CBOR with a fixed
context — see [HintClaim].
| Field | Type | Description |
|---|---|---|
home_server | string | Required. The album’s home server, which sends and signs the hint, as its own server-info names it. |
recipient_server | string | Required. The server the hint is addressed to — this one, as its own server-info names it. |
nonce | string | Required. A value the peer never signs twice: 16 to 64 bytes, a UUID being the obvious choice. |
album_id | string | Required. The album that has news, as its home server names it. |
sent_at | string | Required. When the peer signed the hint, RFC 3339. Refused when more than five minutes from this server’s clock either way. |
signature | string | Required. The peer’s Ed25519 signature over the canonical CBOR of the fields above and the context capsule-federation-hint-v1, base64. |
PullHintResponse
Section titled “PullHintResponse”An accepted hint.
Says when it was received and nothing else: in particular not whether this server pulls the album, which a hint must never be a way to learn.
| Field | Type | Description |
|---|---|---|
received_at | string | Required. When this server accepted the hint, RFC 3339. |
PulledAssetView
Section titled “PulledAssetView”One asset of a pulled album: its breadcrumb, built from the latest entry this server’s pull accepted for it.
| Field | Type | Description |
|---|---|---|
asset_id | string | Required. The asset, as its home server names it. |
head | string | Required. Its chain head: the hash of its latest accepted provenance record, lowercase hex. |
timestamp | string | Required. When the head record says it was written, RFC 3339. Self-asserted by its author. |
author | string | Required. The account that wrote the head record, on the album’s home server. |
size | integer | Required. The asset’s plaintext size in bytes. |
PulledAssetsResponse
Section titled “PulledAssetsResponse”A page of the assets this server pulled for one of the caller’s subscriptions.
| Field | Type | Description |
|---|---|---|
peer | string | Required. The album’s home server. |
album_id | string | Required. The album, as its home server names it. |
assets | PulledAssetView[] | Required. The album’s live assets after after, by asset id in byte order. Deleted and purged assets are not listed. |
next_after | string | null | The after that asks for the next page; absent once a page came back short, so the album has been listed to its end. |
RefreshedCapabilityResponse
Section titled “RefreshedCapabilityResponse”A refreshed capability.
| Field | Type | Description |
|---|---|---|
token | string | Required. The successor token. |
jti | string | Required. Its identifier. |
expires_at | string | Required. When this token stops being honoured, RFC 3339. |
not_after | string | Required. When the whole grant dies, RFC 3339 — unchanged by this or any refresh. |
replayed | boolean | Required. Whether this call issued the successor, or answered one an earlier call already issued. Advisory. A peer never branches on it: both answers mean “here is the token to keep pulling with”. |
SubscribeRequest
Section titled “SubscribeRequest”The subscription request: the capability a member’s client received in a share invite.
| Field | Type | Description |
|---|---|---|
issuer | string | Required. The album’s home server, which minted the capability, as its own server-info names itself (home.tld). |
token | string | Required. The capability, exactly as the invite carried it. |
SubscriptionView
Section titled “SubscriptionView”One subscription, as its subscriber sees it. Never the token.
| Field | Type | Description |
|---|---|---|
peer | string | Required. The album’s home server, which every pull fetches from. |
album_id | string | Required. The album, as its home server names it. |
scope | WireScope | Required. What the capability permits. |
jti | string | Required. The capability’s jti. |
issued_at | string | Required. When the capability was issued, RFC 3339. |
expires_at | string | Required. When the capability stops being honoured, RFC 3339. |
subscribed_at | string | Required. When this subscription was first recorded, RFC 3339. |
live | boolean | Required. Whether the capability is still honoured, so the album is still being pulled. false means the capability lapsed before anything renewed it; posting a fresh invite revives the subscription. |
SubscriptionsResponse
Section titled “SubscriptionsResponse”The caller’s subscriptions.
| Field | Type | Description |
|---|---|---|
subscriptions | SubscriptionView[] | Required. Every subscription, live or lapsed, ordered by peer and then album. |
WireScope
Section titled “WireScope”What a capability permits, on the wire.
A mirror of [Scope] rather than the type itself, for the reason
WireBlobRole is one: the domain enum is not a schema
type, and the wire spelling is a contract that should not move when an internal name does.
One of: read, read-derivative-only.