Skip to main content
POST
/
recordings
/
{id}
/
upload-complete
curl -X POST https://api.bota.dev/v1/recordings/rec_abc123/upload-complete \
  -H "Authorization: Bearer sk_live_..."
{
  "id": "rec_abc123",
  "device_id": "dev_abc123",
  "end_user_id": "eu_xyz789",
  "name": "Product interview - Jane Doe",
  "status": "uploaded",
  "duration_ms": 1800000,
  "started_at": "2025-01-15T09:00:00Z",
  "ended_at": "2025-01-15T09:30:00Z",
  "transcription_id": null,
  "media": [
    {
      "id": "med_001",
      "type": "audio",
      "mime_type": "audio/opus",
      "file_size_bytes": 2048576,
      "status": "uploaded",
      "captured_at": "2025-01-15T09:00:00Z",
      "created_at": "2025-01-15T10:00:00Z"
    },
    {
      "id": "med_002",
      "type": "image",
      "mime_type": "image/jpeg",
      "file_size_bytes": 245000,
      "status": "uploaded",
      "captured_at": "2025-01-15T09:05:30Z",
      "created_at": "2025-01-15T10:01:00Z"
    }
  ],
  "metadata": {
    "meeting_type": "interview"
  },
  "created_at": "2025-01-15T10:00:00Z"
}
Mark the recording upload as complete after all files have been uploaded to S3. This transitions the recording status from pending to uploaded and fires an event for downstream processing (e.g., transcription).

Authentication

This endpoint accepts two authentication methods:
AuthUse case
API keyBackend uploading on behalf of devices (BLE sync)
Device token4G/WiFi devices uploading directly
curl -X POST https://api.bota.dev/v1/recordings/rec_abc123/upload-complete \
  -H "Authorization: Bearer sk_live_..."

Path Parameters

id
string
required
The recording’s unique identifier (e.g., rec_abc123).

Response

Returns the updated recording object with status set to uploaded.
{
  "id": "rec_abc123",
  "device_id": "dev_abc123",
  "end_user_id": "eu_xyz789",
  "name": "Product interview - Jane Doe",
  "status": "uploaded",
  "duration_ms": 1800000,
  "started_at": "2025-01-15T09:00:00Z",
  "ended_at": "2025-01-15T09:30:00Z",
  "transcription_id": null,
  "media": [
    {
      "id": "med_001",
      "type": "audio",
      "mime_type": "audio/opus",
      "file_size_bytes": 2048576,
      "status": "uploaded",
      "captured_at": "2025-01-15T09:00:00Z",
      "created_at": "2025-01-15T10:00:00Z"
    },
    {
      "id": "med_002",
      "type": "image",
      "mime_type": "image/jpeg",
      "file_size_bytes": 245000,
      "status": "uploaded",
      "captured_at": "2025-01-15T09:05:30Z",
      "created_at": "2025-01-15T10:01:00Z"
    }
  ],
  "metadata": {
    "meeting_type": "interview"
  },
  "created_at": "2025-01-15T10:00:00Z"
}

Response Fields

FieldTypeDescription
idstringThe recording’s unique identifier
device_idstringThe device that created this recording
end_user_idstringThe end user associated with this recording
namestring | nullHuman-readable name for the recording
statusstringRecording status (will be uploaded on success)
duration_msinteger | nullDuration of the recording in milliseconds
started_atstringISO 8601 timestamp when the recording started
ended_atstringISO 8601 timestamp when the recording ended
transcription_idstring | nullAssociated transcription ID, if any
mediaarrayFiles associated with this recording
media[].idstringMedia identifier (med_*)
media[].typestringMedia type: audio, image, or video
media[].mime_typestringMIME type of the file
media[].file_size_bytesintegerFile size in bytes
media[].statusstringUpload status: pending, uploaded
media[].captured_atstring | nullISO 8601 timestamp of when the media was captured
media[].created_atstringISO 8601 timestamp of when the media record was created
metadataobjectCustom metadata attached to the recording
created_atstringISO 8601 timestamp when the recording was created

Complete Upload Flow

// 1. Create recording
const recording = await createRecording({ device_id: 'dev_abc123' });

// 2. Upload audio
const audio = await getUploadUrl(recording.id, { type: 'audio', content_type: 'audio/opus' });
await uploadToS3(audio.upload_url, audioBuffer, 'audio/opus');

// 3. Upload images (optional)
const image = await getUploadUrl(recording.id, {
  type: 'image',
  content_type: 'image/jpeg',
  captured_at: '2025-01-15T09:05:30Z',
});
await uploadToS3(image.upload_url, imageBuffer, 'image/jpeg');

// 4. Mark complete — fires event for downstream processing
const updated = await completeUpload(recording.id);
console.log(updated.status); // 'uploaded'
The recording must be in pending status. Calling this on an already-uploaded recording returns a 400 error.