Skip to main content
POST
Call this endpoint only after the S3 PUT succeeds. When content_sha256 is supplied, Bota independently reads the stored object and returns 425 while verification is pending. Retry the identical request with a delay and a bounded deadline. Only 200 confirms completion; retain the source if the deadline expires.
Treat only 200 as permission to delete the recoverable source. 425 means the object is stored but server verification has not completed. A SHA mismatch changes the recording to integrity_failure; request a fresh upload URL and upload the complete source again.

Authentication

This endpoint accepts either an API key or a device token.

Path Parameters

string
required
The recording’s unique identifier.

Request Body

integer
Duration of the uploaded audio in seconds.
integer
Uploaded file size in bytes.
string
SHA-256 of the exact bytes sent in the S3 PUT, as 64 lowercase hex characters. When supplied, a successful response is gated on server-side verification.
string
Optional diagnostic identifier for this upload attempt (1–64 characters: letters, digits, period, underscore, colon or hyphen). Reuse it on completion retries; use a new value for a new PUT attempt. It does not change idempotency.
string
Optional client name/version for diagnostics (1–64 characters: letters, digits, period, underscore, colon, plus or hyphen). Do not include credentials or personal data.

Handling verification failures

409 upload_integrity_failed means the stored bytes failed verification. Keep the source, request a fresh upload URL, PUT the complete file again, then call completion with the SHA-256 and length of those exact bytes. Bound whole-file retries too; repeated mismatch needs investigation. Do not replace the declared hash with a server-reported hash merely to force acceptance. Capture the recording ID, upload attempt ID, client version, PUT byte count and SHA-256, completion request ID, and HTTP status in client diagnostics. If a device also supplied a hash, compare it with the staged file before accepting the transfer. Keep both values for diagnosis without logging audio, credentials, or signed URLs. Bota worker logs record expected/actual hashes, byte counts and the S3 version/ETag from the same read. Asynchronous verification errors appear in worker logs; the earlier HTTP request can legitimately show 425 in API Logs.

Response

Returns the updated recording object. With content_sha256, 200 means content_sha256_verified_at has been set. Until then the endpoint returns 425 upload_verification_pending; clients should retry with backoff without re-uploading. Without a supplied hash, no integrity check runs. An exact retry after a lost or timed-out success response also returns 200 with the already uploaded recording. The replay does not repeat storage usage, recording.uploaded, auto-enhancement, auto-transcription, or integrity-queue side effects. If supplied duration, size, or SHA-256 conflicts with a stored non-null value, the endpoint returns 409. An already processed completion is not itself a conflict. Retrying the same duration, byte count, and SHA-256 after verification succeeds must return 200. For a device recording whose backend policy has reached applied v2_required, the first legacy completion is rejected with 409 and error code encrypted_upload_v2_required, even when an older permissive credential was issued. Any rejected unpublished plaintext final object is removed.
The first completion must be in pending state with an assigned storage key. An exact replay is accepted from uploaded after verification. After integrity_failure, obtain a new upload URL, repeat the full PUT, then retry completion. Other incompatible states return 400.

Ambiguous Responses

If the response is lost or times out, retry the exact request. The server serializes the transition and returns the stored uploaded recording. A changed request is not a replay: conflicting stored evidence returns 409. The Idempotency-Key header is not required for this recording-scoped behavior. Already acknowledged legacy uploads can be replayed after a policy change, without issuing a new upload credential. Published encrypted-upload-v2 rows must use their session protocol and cannot be patched through this endpoint. Zero duration is accepted for a recording shorter than one second. Suppressing replayed effects does not provide a transactional, exactly-once outbox for a server crash between the committed transition and its downstream effects.