Skip to content

Federation

Stable

Generated 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.

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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-Signatureheaderstring | nullt=<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-SchemaheaderintegerThe sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400.
StatusBodyDescription
200RefreshedCapabilityResponse
application/json
OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
400CodedProblem
application/problem+json
Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
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.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
409CodedProblem
application/problem+json
Member not on roster. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
425CodedProblem
application/problem+json
Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
426CodedProblem
application/problem+json
Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
429CodedProblem
application/problem+json
Rate budget exceeded. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
500CodedProblem
application/problem+json
Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.

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 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 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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-SchemaheaderintegerThe 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

StatusBodyDescription
202PullHintResponse
application/json
The hint was received. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
400CodedProblem
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.
401CodedProblem
application/problem+json
Hint unsigned. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
application/problem+json
Peer unknown; Server blocked. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
415CodedProblem
application/problem+json
Unsupported Media Type. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
422CodedProblem
application/problem+json
Unprocessable Entity. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
425CodedProblem
application/problem+json
Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
426CodedProblem
application/problem+json
Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
429CodedProblem
application/problem+json
Hint rate limited. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
500CodedProblem
application/problem+json
Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.

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.

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).

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.

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.

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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-SchemaheaderintegerThe 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

StatusBodyDescription
202FederatedReportResponse
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.
400CodedProblem
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.
401CodedProblem
application/problem+json
Report unsigned. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
application/problem+json
Peer unknown; Server blocked. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
415CodedProblem
application/problem+json
Unsupported Media Type. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
422CodedProblem
application/problem+json
Unprocessable Entity. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
425CodedProblem
application/problem+json
Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
426CodedProblem
application/problem+json
Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
429CodedProblem
application/problem+json
Report rate limited. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
500CodedProblem
application/problem+json
Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.

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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-SchemaheaderintegerThe sidecar schema version declared at sidecar_schema field 0. Sent on metadata updates; a schema newer than this server indexes is refused with 400.
StatusBodyDescription
200SubscriptionsResponse
application/json
OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
400CodedProblem
application/problem+json
Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
application/problem+json
Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
500CodedProblem
application/problem+json
Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.

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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-SchemaheaderintegerThe 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

StatusBodyDescription
200SubscriptionView
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.
201SubscriptionView
application/json
The subscription was recorded. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
400CodedProblem
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.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
application/problem+json
Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
415CodedProblem
application/problem+json
Unsupported Media Type. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
422CodedProblem
application/problem+json
Unprocessable Entity. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
425CodedProblem
application/problem+json
Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
426CodedProblem
application/problem+json
Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
500CodedProblem
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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-SchemaheaderintegerThe 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_idpathstringRequired. The album, as its home server names it.
peerpathstringRequired. The album’s home server.
StatusBodyDescription
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.
400CodedProblem
application/problem+json
Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
application/problem+json
Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
425CodedProblem
application/problem+json
Too early. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
426CodedProblem
application/problem+json
Protocol version unsupported. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
500CodedProblem
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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-SchemaheaderintegerThe 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_idpathstringRequired. The album, as its home server names it.
peerpathstringRequired. The album’s home server.
afterquerystring | nullResume after this asset id: the next_after the previous page answered. Absent starts from the first asset.
limitqueryinteger | nullHow many assets to answer: 100 when absent, and clamped into 1 to 1,000.
StatusBodyDescription
200PulledAssetsResponse
application/json
OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
400CodedProblem
application/problem+json
Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
application/problem+json
Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
500CodedProblem
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.

ParameterInTypeDescription
X-Capsule-Crypto-SuiteheaderintegerThe crypto suite id from the primitives inventory. Sent on writes; a suite this server does not implement is refused with 400.
X-Capsule-ProtocolheaderstringRequired. 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-SchemaheaderintegerThe 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_idpathstringRequired. The album, as its home server names it.
asset_idpathstringRequired. The asset, as its home server names it.
peerpathstringRequired. The album’s home server.
StatusBodyDescription
200string
application/octet-stream
OK. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
400CodedProblem
application/problem+json
Bad Request; Malformed handshake. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
403CodedProblem
application/problem+json
Forbidden. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
404CodedProblem
application/problem+json
Not found. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.
413CodedProblem
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.
500CodedProblem
application/problem+json
Internal server error. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id.

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.

An RFC 9457 problem detail.

FieldTypeDescription
typestringRequired.
titlestring—
statusintegerRequired.
detailstring—
instancestring—
codestringRequired. The stable error.* catalog code. The client localizes this; detail stays English. Present on every problem this server renders.
request_idstringThe 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.

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].

FieldTypeDescription
reporting_serverstringRequired. The peer filing the report, as its own server-info names it.
recipient_serverstringRequired. The server the report is addressed to — this one, as its own server-info names it.
noncestringRequired. A value the peer never signs twice: 16 to 64 bytes, a UUID being the obvious choice.
reported_userstringRequired. The account on this server the report is about.
asset_hashstringRequired. The content address of the asset complained about.
album_idstringRequired. The album it was pulled from.
reasonstring | nullA short reason, where the peer gives one.
reported_atstringRequired. When the peer signed the report, RFC 3339. Refused when more than five minutes from this server’s clock either way.
signaturestringRequired. The peer’s Ed25519 signature over the canonical CBOR of the fields above, base64.

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.

FieldTypeDescription
report_idstringRequired. This server’s identifier for the report.
received_atstringRequired. When this server accepted it, RFC 3339.

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].

FieldTypeDescription
home_serverstringRequired. The album’s home server, which sends and signs the hint, as its own server-info names it.
recipient_serverstringRequired. The server the hint is addressed to — this one, as its own server-info names it.
noncestringRequired. A value the peer never signs twice: 16 to 64 bytes, a UUID being the obvious choice.
album_idstringRequired. The album that has news, as its home server names it.
sent_atstringRequired. When the peer signed the hint, RFC 3339. Refused when more than five minutes from this server’s clock either way.
signaturestringRequired. The peer’s Ed25519 signature over the canonical CBOR of the fields above and the context capsule-federation-hint-v1, base64.

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.

FieldTypeDescription
received_atstringRequired. When this server accepted the hint, RFC 3339.

One asset of a pulled album: its breadcrumb, built from the latest entry this server’s pull accepted for it.

FieldTypeDescription
asset_idstringRequired. The asset, as its home server names it.
headstringRequired. Its chain head: the hash of its latest accepted provenance record, lowercase hex.
timestampstringRequired. When the head record says it was written, RFC 3339. Self-asserted by its author.
authorstringRequired. The account that wrote the head record, on the album’s home server.
sizeintegerRequired. The asset’s plaintext size in bytes.

A page of the assets this server pulled for one of the caller’s subscriptions.

FieldTypeDescription
peerstringRequired. The album’s home server.
album_idstringRequired. The album, as its home server names it.
assetsPulledAssetView[]Required. The album’s live assets after after, by asset id in byte order. Deleted and purged assets are not listed.
next_afterstring | nullThe after that asks for the next page; absent once a page came back short, so the album has been listed to its end.

A refreshed capability.

FieldTypeDescription
tokenstringRequired. The successor token.
jtistringRequired. Its identifier.
expires_atstringRequired. When this token stops being honoured, RFC 3339.
not_afterstringRequired. When the whole grant dies, RFC 3339 — unchanged by this or any refresh.
replayedbooleanRequired. 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”.

The subscription request: the capability a member’s client received in a share invite.

FieldTypeDescription
issuerstringRequired. The album’s home server, which minted the capability, as its own server-info names itself (home.tld).
tokenstringRequired. The capability, exactly as the invite carried it.

One subscription, as its subscriber sees it. Never the token.

FieldTypeDescription
peerstringRequired. The album’s home server, which every pull fetches from.
album_idstringRequired. The album, as its home server names it.
scopeWireScopeRequired. What the capability permits.
jtistringRequired. The capability’s jti.
issued_atstringRequired. When the capability was issued, RFC 3339.
expires_atstringRequired. When the capability stops being honoured, RFC 3339.
subscribed_atstringRequired. When this subscription was first recorded, RFC 3339.
livebooleanRequired. 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.

The caller’s subscriptions.

FieldTypeDescription
subscriptionsSubscriptionView[]Required. Every subscription, live or lapsed, ordered by peer and then album.

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.