Snapshot publishing API
Create an upload with POST /api/v1/snapshot-uploads and {filename, byteSize}. PUT the raw .cap bytes to the returned signed URL, then call POST /api/v1/snapshot-uploads/{uploadId}/complete. It returns 202 with status: "queued" at once; verification runs in the background. Poll GET /api/v1/snapshot-uploads/{uploadId} until status is complete (with snapshot ID and share URL) or rejected (with the validation report). If it returns to uploading with a report, verification could not finish; call complete again. Each API key is rate limited (120 requests per 60 seconds; the counter resets only after 60 idle seconds), so back off while polling (for example from 3 to 15 seconds) and on 429 wait for Retry-After before continuing.
Use GET /api/v1/snapshots/{snapshotId} for metadata and /download for the original archive. Objects are available only if that snapshot lists them as included. /files groups the files by top-level directory (add ?dir=<name> for one directory), and /records/{recordId} returns one raw record from the snapshot.
For key binding, request POST /api/account/signing-keys/challenges with {key} (session or an API key with account permission). The response proof is a four-line key-proof text; sign the SHA-256 of its UTF-8 bytes with cap.signature/3 (signKeyProof in @hypoark/cap/signing), then POST {challengeId, signature} to /api/account/signing-keys. Do not sign the raw challenge. Challenges expire after five minutes and may be consumed once.