Guest drops
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 /d/{opaque_id}
Section titled “POST /d/{opaque_id}”Open a drop session through a link.
Invariants 26–30 in order: the link admits the file and reserves its caps in one store
operation, then the owner’s quota is charged, then the declaration is checked. A drop the
owner’s quota will not admit is 403 error.quota.exceeded, or 403 error.quota.suspended
while the operator has suspended the owner’s quota.
Authentication: none.
| Parameter | In | Type | Description |
|---|---|---|---|
opaque_id | path | string | Required. The opaque id. |
Request body (required, application/json): CreateDropRequest
| Status | Body | Description |
|---|---|---|
201 | CreateDropResponse application/json | A drop session is open and accepting chunks. 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 drop. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
403 | CodedProblem application/problem+json | Passphrase required; Quota exceeded; Quota suspended. 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 | Link capacity exhausted. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
413 | FileTooLargeProblem application/problem+json | Payload Too Large; File 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. |
429 | DropRateLimitedProblem application/problem+json | Too many requests. Headers: Retry-After, 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 /d/{opaque_id}/{upload_id}
Section titled “GET /d/{opaque_id}/{upload_id}”Report a drop session’s state, and its deposit’s outcome once it has one.
The completing chunk is answered waiting_for_processing before the deposit’s re-hash runs,
so this is where a guest learns whether the drop was filed or refused: completed, or
failed_processing with the deposit’s error.* code. A guest polls it with backoff.
Authorized exactly as a chunk is: the link’s opaque id, live for chunks, plus a session that is a drop under that link’s owner. Read-only — it starts nothing, so polling it cannot change what it reports — and it charges no limiter: it reveals nothing the holder of the two ids does not already own, and a poll spending the per-source budget would refuse the guest’s next drop.
Authentication: none.
| Parameter | In | Type | Description |
|---|---|---|---|
opaque_id | path | string | Required. The opaque id of the link the session belongs to. |
upload_id | path | string | Required. The session id. |
| Status | Body | Description |
|---|---|---|
200 | DropStatusResponse application/json | The drop session’s state. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request. 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. |
PATCH /d/{opaque_id}/{upload_id}
Section titled “PATCH /d/{opaque_id}/{upload_id}”Append one chunk to a drop session.
The link is the credential: possession of the opaque id, plus a session that belongs to it.
Everything after that is [crate::upload::chunk::write_range] — the album path’s own
function.
Authentication: none.
| Parameter | In | Type | Description |
|---|---|---|---|
X-Capsule-Checksum | header | string | null | The chunk’s SHA-256, bare lowercase hex. Required: the idempotency tuple is undefined without it. |
X-Capsule-Offset | header | string | null | Where in the blob this chunk starts. |
opaque_id | path | string | Required. The opaque id of the link the session belongs to. |
upload_id | path | string | Required. The session id. |
Request body (required, application/octet-stream): string
| Status | Body | Description |
|---|---|---|
204 | — | the request succeeded and there is no content to send. Headers: X-Capsule-Min-Client-Build, X-Capsule-Offset, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Capsule-Upload-Status, X-Request-Id. |
400 | CodedProblem application/problem+json | Bad Request; Malformed request; Malformed chunk. 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. |
408 | CodedProblem application/problem+json | Request timeout. Headers: X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
409 | CodedProblem application/problem+json | Chunk refused. 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. |
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. |
425 | CodedProblem application/problem+json | Too early. 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. |
503 | DropChunkUnavailableProblem application/problem+json | Service unavailable. Headers: Retry-After, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
507 | DropChunkStorageFullProblem application/problem+json | Insufficient storage. Headers: Retry-After, X-Capsule-Min-Client-Build, X-Capsule-Protocol-Max, X-Capsule-Protocol-Min, X-Request-Id. |
GET /v1/drops
Section titled “GET /v1/drops”The caller’s pending drops.
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 | InboxResponse 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. |
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/drops/links
Section titled “POST /v1/drops/links”Provision an upload link.
A link is metadata growth: an owner past their quota grace window is refused
403 error.quota.grace_locked, and one whose quota the operator suspended
403 error.quota.suspended.
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): ProvisionLinkRequest
| Status | Body | Description |
|---|---|---|
201 | ProvisionLinkResponse application/json | The upload link is provisioned and accepting drops. 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 upload link; 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; Quota grace expired; Quota suspended. 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/drops/links/{opaque_id}
Section titled “DELETE /v1/drops/links/{opaque_id}”Revoke one of the caller’s links.
Never consults the quota: a revocation frees nothing but is admitted in every state, suspended and past the grace window included.
Indistinguishable and idempotent, for the same reason a share revocation is: saying “there was nothing to revoke” would be a lookup.
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. |
opaque_id | path | string | Required. The opaque id. |
| 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 upload link; 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; Quota grace expired; Quota suspended. 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. |
DELETE /v1/drops/{drop_id}
Section titled “DELETE /v1/drops/{drop_id}”Discard a pending drop.
The bytes become unreferenced and the collector reclaims them; the link’s cap is not refunded, because the drop did happen — a guest deposited a file and the owner chose not to keep it, which is not the same as a link slot never having been used.
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. |
drop_id | path | string | Required. The drop’s identifier. |
| 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. |
POST /v1/drops/{drop_id}/adopt
Section titled “POST /v1/drops/{drop_id}/adopt”Adopt a pending drop into an album.
Invariant 32. The manifest re-runs the create battery — a drop that skipped it would be the
one write on this server that entered an album unvalidated — and its ciphertext_hash must
name a blob in the caller’s own inbox, which is what stops an adoption from minting an
asset over somebody else’s bytes.
The row is claimed, written, then settled. Across two ports there is no transaction, and
the two failure directions are not equal: writing first and deleting after can duplicate a
photo, taking first and failing to write loses one. A claim leaves a crash visible in the
owner’s own inbox instead, marked adopting.
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. |
drop_id | path | string | Required. The drop’s identifier. |
Request body (required, application/json): AdoptRequest
| Status | Body | Description |
|---|---|---|
200 | AdoptResponse 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; Adoption refused; 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. |
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.
AdoptRequest
Section titled “AdoptRequest”The owner’s signed create over a drop already in their inbox.
The same shape a POST /v1/upload create carries, minus everything about transferring bytes:
the blob is already committed, so there is no size to negotiate and no session to open. What
remains is the manifest, which is the whole point — a drop becomes an asset only when the
owner signs for it.
| Field | Type | Description |
|---|---|---|
album_id | string | Required. The album to adopt into. |
asset_id | string | Required. The asset the drop becomes. |
size | integer | Required. The blob’s declared size — the inbox row’s, restated and checked against it. |
hash | string | Required. The ciphertext hash, which must name this drop’s blob. |
content_type | string | Required. The declared content type. |
crypto_suite_id | integer | Required. The crypto suite. |
protocol_version | string | Required. The protocol version the manifest is written against. |
key_mode | string | Required. How the asset’s key is carried. derived or wrapped (invariant 32). |
manifest_envelope | ManifestEnvelope | Required. The signed manifest envelope, verbatim. |
AdoptResponse
Section titled “AdoptResponse”What adoption produced.
| Field | Type | Description |
|---|---|---|
asset_id | string | Required. The asset the drop became. |
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. |
CreateDropRequest
Section titled “CreateDropRequest”A guest’s declared drop.
No album_id, no amk_version, no manifest, no provenance. deny_unknown_fields is
what enforces invariant 30’s absence clause: a drop that names an album is a 400 rather
than a field the server quietly ignores, because ignoring it would let a guest believe they
had written into an album.
| Field | Type | Description |
|---|---|---|
content_type | string | Required. The declared content type, from the link’s pinned protocol enum (invariant 27). |
size | integer | Required. The ciphertext’s total length. |
ciphertext_hash | string | Required. The lowercase-hex SHA-256 finalization verifies against. |
kem_ct | string | Required. K encapsulated to the link’s Drop Key, base64. Length fixed by the suite (invariant 30). |
passphrase_proof | string | null | The Argon2id proof for a passphrase-gated link, base64. Required exactly when the link carries a verifier, and absent otherwise. The passphrase itself is never transmitted: what travels is the derived proof, and the KDF’s cost is what rate-limits guessing on top of the per-link limiter. It gates a write and adds no confidentiality — the guest already encrypts every asset. What it limits is who may spend the owner’s quota (Web Upload). |
suggested_filename | string | null | Guest-supplied and unverified. Advisory only. |
CreateDropResponse
Section titled “CreateDropResponse”The session a guest uploads into.
| Field | Type | Description |
|---|---|---|
upload_id | string | Required. The session id, and the last path segment of the chunk endpoint. |
suggested_chunk_size | integer | Required. The chunk size to start with. |
DropChunkStorageFullProblem
Section titled “DropChunkStorageFullProblem”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. |
retry_after | integer | When the guest may retry, as Unix seconds; the Retry-After header carries the same instant as a delay. The guest waits, then resends the same chunk at the same offset. |
DropChunkUnavailableProblem
Section titled “DropChunkUnavailableProblem”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. |
retry_after | integer | When the guest may retry, as Unix seconds; the Retry-After header carries the same instant as a delay. The guest waits, then resends the same chunk at the same offset. |
DropRateLimitedProblem
Section titled “DropRateLimitedProblem”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. |
retry_after | integer | When the caller may retry, as Unix seconds. From the limiter’s own window when a budget is spent, and an upper bound of one window when the limiter is at capacity. |
DropStatusResponse
Section titled “DropStatusResponse”What a guest’s drop session is doing, as its status probe reports it.
The session’s own state and nothing else: no drop id, no owner, no link totals. Every field is one the guest already holds or is owed — the bytes they sent, the size they declared, and the outcome of the deposit they started.
| Field | Type | Description |
|---|---|---|
status | string | Required. Where the session is in its state machine: pending, uploading, waiting_for_processing while its deposit runs, then completed once the drop is in its owner’s inbox, or failed_processing once the deposit refused it. |
received_bytes | integer | Required. Bytes durably accepted so far — the offset a resumed upload continues from. |
total_size | integer | Required. The declared total. |
error_code | string | null | For a failed_processing session, the error.* code the deposit failed with. Absent for every other state. |
FileTooLargeProblem
Section titled “FileTooLargeProblem”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. |
limit | integer | The largest file this drop link accepts, in bytes. |
InboxEntryResponse
Section titled “InboxEntryResponse”One drop waiting for the owner.
| Field | Type | Description |
|---|---|---|
drop_id | string | Required. The drop’s identifier, which adoption and discard name. |
opaque_id | string | Required. The link it arrived through. |
ciphertext_hash | string | Required. The ciphertext’s content address. |
size | integer | Required. How many bytes. |
content_type | string | Required. The guest’s declared content type. |
kem_ct | string | Required. K encapsulated to the link’s Drop Key, base64. The owner decapsulates. |
suggested_filename | string | null | Guest-supplied and unverified. A guest chose this text. A client rendering it treats it as untrusted input — it is the one field on this surface an anonymous party authored. |
received_at | string | Required. When it landed, RFC 3339. |
adopting | boolean | Required. Whether an adoption currently holds this row. Surfaced rather than hidden: a crash between claim and settle leaves a row here, and an owner who cannot see it cannot act on it. |
InboxResponse
Section titled “InboxResponse”The owner’s pending drops.
| Field | Type | Description |
|---|---|---|
drops | InboxEntryResponse[] | Required. Everything waiting, oldest first. |
ManifestEnvelope
Section titled “ManifestEnvelope”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.
| Field | Type | Description |
|---|---|---|
crypto_suite_id | integer | Required. The crypto suite the blob was sealed under. Must equal the top-level declaration. |
protocol_version | string | Required. The protocol date the manifest was written under (YYYY-MM-DD). |
album_id | string | null | The album the asset belongs to. Must equal the top-level declaration. |
file_id | string | Required. The asset this blob belongs to — the same id across the bundle’s members. |
amk_version | integer | Required. The album-key epoch the manifest was written under. |
ciphertext_hash | string | Required. 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. |
plaintext_size | integer | Required. The plaintext length the manifest commits to. |
chunk_size | integer | Required. The STREAM plaintext chunk size. |
key_mode | string | Required. derived or wrapped. |
metadata_blob_hash | string | null | The content hash of the bundle’s metadata blob, when the manifest commits to one. |
original_blob_hash | string | null | The content hash of the bundle’s original blob, when the manifest commits to one. 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. |
derivative_role | string | null | The derivative’s role — thumbnail, preview, or embedding — copied from its signed DerivativeManifest.role. Required on a derivative blob and refused on every other. The server cannot read the signed derivative manifest (it is key-free), so the closed still-format check the tier table requires of every receiver runs over this declared pair instead. A forged pair buys nothing: the client that verifies the signed manifest runs the same check over the signed values. |
derivative_format | string | null | The derivative’s format — DerivativeManifest.format, e.g. image/jxl. Required and refused exactly as [Self::derivative_role] is, and must equal the blob’s declared content_type. For a thumbnail or preview an unrecognised value is [GateReject::UnknownDerivativeFormat]. |
created_by_user | string | Required. The account that created the asset. |
created_by_device | string | Required. The device that created it, as a UUID — invariant 7’s subject. |
client_version | string | Required. The client build that wrote the manifest. |
timestamp | string | Required. The manifest’s self-asserted RFC3339 timestamp — invariants 7 and 8’s subject. |
action | string | Required. The lifecycle action. create or replace on this surface — the two that move blob bytes — and see [GateReject::ActionNotAllowed] for the rest. |
prior_provenance_hash | string | null | The provenance chain position this write continues from. |
retention_until | string | null | The retention floor the manifest carries, when it carries one. |
ProvisionLinkRequest
Section titled “ProvisionLinkRequest”A link the owner is provisioning.
| Field | Type | Description |
|---|---|---|
opaque_id | string | Required. The 128-bit opaque id, 32 lowercase hex characters, from the client’s CSPRNG. |
drop_pubkey | string | Required. The Drop Key’s public half, base64. Opaque here — the server never decapsulates. |
crypto_suite_id | integer | Required. The suite a drop must be sealed under. |
expires_at | string | null | When the link stops accepting drops, RFC 3339. |
max_total_bytes | integer | null | Cumulative bytes across every drop on this link. |
max_file_count | integer | null | How many files the link may deposit. |
max_file_size | integer | null | The largest single file. |
single_use | boolean | Whether the link dies after its first successful drop. |
passphrase_verifier | string | null | An Argon2id verifier, base64, when the link is passphrase-gated. A verifier and never a passphrase: this is an abuse gate the server checks, which is why it is stored here at all — unlike a share link’s passphrase, which protects decryption and which the server never sees in any form. |
ProvisionLinkResponse
Section titled “ProvisionLinkResponse”Confirmation that a link is live.
| Field | Type | Description |
|---|---|---|
opaque_id | string | Required. The opaque id, echoed. |