Skip to content

Storage verification

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.

Fetch every custody receipt covering one asset.

Authentication: required — bearer.

ParameterInTypeDescription
asset_idpathstringRequired. The asset id.
StatusBodyDescription
200AssetReceiptsResponse
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.

Confirm that the server holds the copies a client is about to stop holding.

A pure read: it writes no blob, no index row and no verdict. Soundness against a racing collection comes from the standing GC grace window rather than from a per-request lease, which is why nothing here takes one.

Authentication: required — bearer.

Request body (required, application/json): StorageVerifyRequest

StatusBodyDescription
200StorageVerifyResponse
application/json
OK.
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.

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.

One custody receipt, decoded, beside the bytes that were signed.

FieldTypeDescription
receipt_seqintegerRequired. Strictly monotonic per server. The chain position this receipt cannot be moved from.
server_idstringRequired. This server’s canonical origin — what binds the receipt to one server.
server_key_idstringRequired. The attestation key fingerprint that signed, hex. Survives rotation, which is why the key is named rather than assumed.
prior_receipt_hashstring | nullSHA-256 of the previous receipt in the server’s log, hex. Absent for the first receipt this server ever issued.
upload_idstringRequired. The upload session that produced custody.
blob_rolestringRequired. original, derivative, metadata or provenance.
ciphertext_hashstringRequired. The server-recomputed ciphertext content address, hex.
sizeintegerRequired. Ciphertext size in bytes.
envelope_hashstring | nullSHA-256 of the asset’s signed manifest, hex — present on the provenance receipt and absent on every other, because the manifest commits to the rest.
received_atstringRequired. The server’s trusted clock at the finalization commit, RFC 3339.
receipt_cborstringRequired. The full signed receipt as canonical CBOR, base64. This is the receipt. Verify the hybrid signature over these bytes under the key server_key_id names, from /.well-known/capsule/attestation-keys; everything above is a reading of them.

The chain.

FieldTypeDescription
asset_idstringRequired. The asset the chain belongs to, echoed so a client batching requests can tell the answers apart.
receiptsAssetReceipt[]Required. Every receipt covering the asset, in receipt_seq order.

One asset to verify, with the exact copies the client is relying on.

FieldTypeDescription
asset_idstringRequired. The asset.
blob_hashesstring[]Required. Every content address the client would be trusting the server with. The verdict is a conjunction over exactly these, so a client asks about what it is about to delete.

One declared blob’s verdict.

FieldTypeDescription
hashstringRequired. The address, as the client declared it.
rolestringRequired. The role the asset holds it under — unknown for a hash the asset does not hold.
storedbooleanRequired. The bytes are present at that address.
indexedbooleanRequired. A live asset of the caller’s references the address.
retrievablebooleanRequired. Nothing is withholding it.
deepstring | nullWhat a deep scan found: intact, corrupt, or rate_limited (S-C41). Absent when no deep scan ran, and the absence is load-bearing: it is the difference between “we did not look at the bytes” and “we looked and they were fine”, and a client deciding whether to release its only copy has to be able to tell those apart.

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.

One asset’s verdict.

FieldTypeDescription
asset_idstringRequired. The asset the client asked about.
durablebooleanRequired. Every declared blob is stored ∧ indexed ∧ retrievable. This is the field that gates a deletion, so it is false whenever the server cannot say otherwise.
blobsBlobVerdictResponse[]Required. One entry per declared hash, in declaration order and never shortened.
checked_atstringRequired. The server’s own clock at verification, RFC 3339. Never the client’s.

The POST /v1/storage/verify body.

FieldTypeDescription
assetsAssetVerifyRequest[]Required. The assets to verify.
deepbooleanAlso re-read and re-hash the bytes (S-C41). Absent or false is the structural check: ask the index and the store whether the bytes are there. true additionally re-hashes them, which is the only way to catch silent corruption — stored is a question about the filesystem, and a corrupt blob is still stored. Rate-limited per account, because a deep scan reads and hashes every declared blob and an unbounded one is an I/O-amplification attack costing the caller one small JSON body. Past the budget the structural verdict still comes back and each blob’s deep reads rate_limited: throwing away a good structural answer because the optional half was throttled would make the limiter cost more than it saves.

The POST /v1/storage/verify response.

FieldTypeDescription
verdictsStorageVerdictResponse[]Required. One verdict per requested asset, in request order.