Skip to content

Albums and lifecycle writes

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.

Bind an album id to the authenticated caller.

Idempotent: the same id from a second device, or after a recovery, is a success that writes nothing.

Authentication: required — bearer.

Request body (required, application/json): ProvisionAlbumRequest

StatusBodyDescription
200ProvisionAlbumResponse
application/json
The album id was already provisioned to this account; nothing was written.
201ProvisionAlbumResponse
application/json
The album was created and bound to the caller.
400CodedProblem
application/problem+json
Bad Request.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate.
403CodedProblem
application/problem+json
Forbidden.
413the request body exceeds the configured limit.
415CodedProblem
application/problem+json
Unsupported Media Type.
422CodedProblem
application/problem+json
Unprocessable Entity.
500CodedProblem
application/problem+json
Internal server error.

Apply one signed lifecycle manifest to an album’s asset.

The whole battery runs before anything is written, and a rejection writes nothing — including the blobs the bundle carries, which are stored only after the manifest has passed every check the server can make without a key.

Authentication: required — bearer.

ParameterInTypeDescription
album_idpathstringRequired. The album’s identifier.

Request body (required, application/json): OpRequest

StatusBodyDescription
200OpResponse
application/json
OK.
400CodedProblem
application/problem+json
Bad Request.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate.
403CodedProblem
application/problem+json
Forbidden.
409StaleRevivalProblem
application/problem+json
Stale revival.
413the request body exceeds the configured limit.
415CodedProblem
application/problem+json
Unsupported Media Type.
422CodedProblem
application/problem+json
Unprocessable Entity.
426ProtocolRangeProblem
application/problem+json
Upgrade required.
500CodedProblem
application/problem+json
Internal server error.

Read the ceremony’s phase and the drain count.

The one call a proposer polls between steps 2 and 4. in_flight reaching zero is the signal that the tombstone may be committed.

Authentication: required — bearer.

ParameterInTypeDescription
album_idpathstringRequired. The album’s id.
StatusBodyDescription
200UpgradePhaseResponse
application/json
OK.
400CodedProblem
application/problem+json
Bad Request.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate.
403CodedProblem
application/problem+json
Forbidden.
404CodedProblem
application/problem+json
Not found.
413the request body exceeds the configured limit.
500CodedProblem
application/problem+json
Internal server error.

Put an album into upgrade quiescence.

Idempotent under its own intent_id: versioning.md is explicit that the same UpgradeIntent never produces two forks, and a proposer that lost an acknowledgement re-POSTs the same bytes.

Authentication: required — bearer.

ParameterInTypeDescription
album_idpathstringRequired. The album’s id.

Request body (required, application/cbor): string

StatusBodyDescription
200UpgradePhaseResponse
application/json
OK.
400CodedProblem
application/problem+json
Bad Request.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate.
403CodedProblem
application/problem+json
Forbidden.
404CodedProblem
application/problem+json
Not found.
409CodedProblem
application/problem+json
Upgrade in flight.
413the request body exceeds the configured limit.
415CodedProblem
application/problem+json
Unsupported media type.
500CodedProblem
application/problem+json
Internal server error.

Abort a ceremony, returning the album to normal operation.

Named by intent_id in the path’s own query so that aborting is a statement about which upgrade — a caller that does not hold the live id gets a 409 rather than the power to cancel somebody else’s ceremony.

Authentication: required — bearer.

ParameterInTypeDescription
album_idpathstringRequired. The album’s id.
intent_idquerystringRequired. The ceremony to abort.
StatusBodyDescription
200UpgradePhaseResponse
application/json
OK.
400CodedProblem
application/problem+json
Bad Request.
401CodedProblem
application/problem+json
Unauthorized. Headers: WWW-Authenticate.
403CodedProblem
application/problem+json
Forbidden.
404CodedProblem
application/problem+json
Not found.
409CodedProblem
application/problem+json
Upgrade in flight.
413the request body exceeds the configured limit.
500CodedProblem
application/problem+json
Internal server error.

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.

The server-visible mirror of the signed manifest’s envelope fields, as declared at POST /v1/upload.

Strict (deny_unknown_fields) like the rest of the transport JSON. The Postel asymmetry the design draws — tolerant inside documents that outlive us, strict on the wire we own — puts unknown-key tolerance in the signed CBOR interiors, never in this JSON projection.

FieldTypeDescription
crypto_suite_idintegerRequired. The crypto suite the blob was sealed under. Must equal the top-level declaration.
protocol_versionstringRequired. The protocol date the manifest was written under (YYYY-MM-DD).
album_idstring | nullThe album the asset belongs to. Must equal the top-level declaration.
file_idstringRequired. The asset this blob belongs to — the same id across the bundle’s members.
amk_versionintegerRequired. The album-key epoch the manifest was written under.
ciphertext_hashstringRequired. The ciphertext content hash, lowercase hex. Must equal the top-level hash. This names the blob this session is uploading, not the manifest’s own ciphertext_hash. For the original the two coincide; for a metadata or provenance session they do not, and the projection reuses the manifest’s field name for a per-blob declaration. Invisible for a create, because the bundle is assembled in a pending row nobody can see and no member has to name another. It is not invisible for a replace, which is why [Self::original_blob_hash] exists (S-C43).
plaintext_sizeintegerRequired. The plaintext length the manifest commits to.
chunk_sizeintegerRequired. The STREAM plaintext chunk size.
key_modestringRequired. derived or wrapped.
metadata_blob_hashstring | nullThe content hash of the bundle’s metadata blob, when the manifest commits to one.
original_blob_hashstring | nullThe content hash of the bundle’s original blob, when the manifest commits to one (S-C43). The manifest’s own ciphertext_hash, under a name that cannot be confused with [Self::ciphertext_hash]‘s per-session meaning. Optional on the wire and required on a replace: a replace re-points roles that already have bytes, so it has to be applied as one act, and the only member of the bundle that can carry the whole change is the manifest — which therefore has to be able to name the original it commits to. A create may omit it. Its bundle is assembled incrementally in a row nobody can see, so no member needs to name another and requiring it would be a wire change for no gain.
created_by_userstringRequired. The account that created the asset.
created_by_devicestringRequired. The device that created it, as a UUID — invariant 7’s subject.
client_versionstringRequired. The client build that wrote the manifest.
timestampstringRequired. The manifest’s self-asserted RFC3339 timestamp — invariants 7 and 8’s subject.
actionstringRequired. The lifecycle action. create or replace on this surface — the two that move blob bytes — and see [GateReject::ActionNotAllowed] for the rest.
prior_provenance_hashstring | nullThe provenance chain position this write continues from.
retention_untilstring | nullThe retention floor the manifest carries, when it carries one.

The signed manifest bundle a lifecycle write carries.

FieldTypeDescription
manifest_envelopeManifestEnvelopeRequired. The server-visible projection of the signed manifest’s fields, exactly as POST /v1/upload carries it. Its album_id must equal the path segment and its action must be one this surface accepts.
manifest_cborstringRequired. The signed manifest itself, base64 of the canonical CBOR. Stored verbatim as the asset’s new provenance blob, so the feed serves the exact bytes the client signed (S-C30) for a lifecycle write as it already does for an upload. The server does not parse it: base64 is a transport encoding, and decode(encode(b)) == b.
metadata_blobstring | nullThe encrypted metadata blob, base64, present exactly when the action carries one. Its content hash must equal the manifest’s committed metadata_blob_hash (invariant 25). The server holds no key and never reads it.

What a lifecycle write did.

FieldTypeDescription
asset_idstringRequired. The asset the op chained onto.
sync_seqintegerRequired. The feed position it occupies. On a replay, the position the first application took.
actionstringRequired. The action that was applied.
replayedbooleanRequired. Whether this response is a replay of an already-applied manifest. Advisory, and deliberately not something a correct client needs: the other three fields are identical either way, which is what “byte-identical prior response” means.

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.
protocol_minstringThe oldest protocol date this server still speaks (YYYY-MM-DD).
protocol_maxstringThe newest protocol date this server speaks (YYYY-MM-DD).

The provisioning request.

FieldTypeDescription
album_idstringRequired. The client-derived album id, as a canonical lowercase hyphenated UUID.

What provisioning did.

FieldTypeDescription
album_idstringRequired. The album, echoed.
protocol_versionstringRequired. The protocol date the album is pinned to — the server’s, fixed at creation.
createdbooleanRequired. Whether this call created the album. Advisory; both answers mean the same thing.

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.
chain_headstring | nullThe manifest hash the asset’s chain is actually at. Absent when the conflict is not a chain conflict, which is why it is nullable.

The ceremony this album is in, as a client polls it.

FieldTypeDescription
album_idstringRequired. The album, echoed.
intent_idstring | nullThe ceremony in flight, or absent when the album is in normal operation. Absent also covers expired: the deadline passing aborts the upgrade, so there is nothing left to be in.
to_protocol_versionstring | nullThe protocol version the fork will be pinned to, when a ceremony is in flight.
expires_atstring | nullWhen the window closes, RFC 3339, on the server’s clock.
in_flightintegerRequired. How many upload sessions are still in flight against this album. The drain signal of versioning.md step 3: the proposer waits for zero. A count rather than a listing, because the proposer needs to know whether to wait and has no business seeing other members’ upload identifiers to find out.