Skip to main content
This page documents all webhook event types, their triggers, and payload schemas.

Event Structure

All events follow this structure:
{
  "id": "evt_abc123def456",
  "type": "event.type",
  "created_at": "2025-01-15T10:30:00Z",
  "data": {
    // Event-specific payload
  }
}
FieldTypeDescription
idstringUnique event identifier. Use for deduplication.
typestringEvent type (e.g., transcription.completed)
created_atstringISO 8601 timestamp of when the event occurred
dataobjectEvent-specific payload (see below)

Recording Events

recording.created

Triggered when a new recording is created via the API.
{
  "id": "evt_abc123",
  "type": "recording.created",
  "created_at": "2025-01-15T10:00:00Z",
  "data": {
    "id": "rec_xyz789",
    "end_user_id": "eu_user123",
    "device_id": "dev_device456",
    "status": "created",
    "consent_obtained": true,
    "metadata": {
      "session_type": "consultation"
    },
    "created_at": "2025-01-15T10:00:00Z"
  }
}
FieldTypeDescription
data.idstringRecording ID
data.end_user_idstringAssociated EndUser
data.device_idstringDevice that will capture the recording
data.statusstringAlways created for this event
data.consent_obtainedbooleanWhether consent was recorded
data.metadataobjectCustom metadata attached to the recording
data.created_atstringWhen the recording was created
Common Use Cases:
  • Track new recordings in your system
  • Initialize processing pipelines
  • Update UI to show recording in progress

recording.uploaded

Triggered when audio upload completes successfully.
{
  "id": "evt_def456",
  "type": "recording.uploaded",
  "created_at": "2025-01-15T10:05:00Z",
  "data": {
    "id": "rec_xyz789",
    "end_user_id": "eu_user123",
    "device_id": "dev_device456",
    "status": "uploaded",
    "duration_seconds": 1847.5,
    "file_size_bytes": 44328000,
    "format": "wav",
    "started_at": "2025-01-15T09:30:00Z",
    "ended_at": "2025-01-15T10:00:47Z",
    "uploaded_at": "2025-01-15T10:05:00Z"
  }
}
FieldTypeDescription
data.idstringRecording ID
data.statusstringAlways uploaded for this event
data.duration_secondsnumberAudio duration in seconds
data.file_size_bytesintegerFile size in bytes
data.formatstringAudio format (wav, mp3, m4a, flac)
data.started_atstringWhen recording started (device time)
data.ended_atstringWhen recording ended (device time)
data.uploaded_atstringWhen upload completed
Common Use Cases:
  • Trigger transcription automatically
  • Update recording status in your UI
  • Calculate storage usage

recording.deleted

Triggered when a recording is deleted via the API.
{
  "id": "evt_rst345",
  "type": "recording.deleted",
  "created_at": "2025-01-15T11:00:00Z",
  "data": {
    "id": "rec_xyz789",
    "deleted_at": "2025-01-15T11:00:00Z"
  }
}
FieldTypeDescription
data.idstringRecording ID that was deleted
data.deleted_atstringWhen the recording was deleted
When a recording is deleted, all associated transcriptions and summaries are also deleted (cascade delete).
Common Use Cases:
  • Clean up local cached data
  • Update UI to remove deleted recordings
  • Audit logging for compliance

Transcription Events

transcription.started

Triggered when transcription processing begins.
{
  "id": "evt_uvw678",
  "type": "transcription.started",
  "created_at": "2025-01-15T10:05:30Z",
  "data": {
    "id": "txn_abc123",
    "recording_id": "rec_xyz789",
    "status": "processing",
    "language": "en",
    "created_at": "2025-01-15T10:05:20Z",
    "started_at": "2025-01-15T10:05:30Z"
  }
}
FieldTypeDescription
data.idstringTranscription ID
data.recording_idstringAssociated recording
data.statusstringAlways processing for this event
data.languagestringLanguage code (specified or auto-detected)
data.started_atstringWhen processing started
Common Use Cases:
  • Show “processing” status in UI
  • Track processing time metrics
  • Trigger dependent workflows

transcription.completed

Triggered when transcription processing completes successfully.
{
  "id": "evt_ghi789",
  "type": "transcription.completed",
  "created_at": "2025-01-15T10:07:00Z",
  "data": {
    "id": "txn_abc123",
    "recording_id": "rec_xyz789",
    "status": "completed",
    "text": "Hello, thank you for coming in today. How can I help you?",
    "duration_seconds": 1847.5,
    "segments": [
      {
        "start": 0.0,
        "end": 2.5,
        "text": "Hello, thank you for coming in today.",
        "speaker": "SPEAKER_00",
        "confidence": 0.95
      },
      {
        "start": 2.8,
        "end": 4.2,
        "text": "How can I help you?",
        "speaker": "SPEAKER_00",
        "confidence": 0.97
      }
    ],
    "speakers": [
      {
        "id": "SPEAKER_00",
        "label": "Speaker 1"
      },
      {
        "id": "SPEAKER_01",
        "label": "Speaker 2"
      }
    ],
    "language": "en",
    "created_at": "2025-01-15T10:05:30Z",
    "completed_at": "2025-01-15T10:07:00Z"
  }
}
FieldTypeDescription
data.idstringTranscription ID
data.recording_idstringAssociated recording
data.statusstringAlways completed for this event
data.textstringFull transcript text
data.duration_secondsnumberAudio duration processed
data.segmentsarrayTimestamped segments with speaker labels
data.segments[].startnumberSegment start time (seconds)
data.segments[].endnumberSegment end time (seconds)
data.segments[].textstringSegment text
data.segments[].speakerstringSpeaker identifier
data.segments[].confidencenumberConfidence score (0-1)
data.speakersarrayList of detected speakers
data.languagestringDetected language code
data.completed_atstringWhen transcription finished
Common Use Cases:
  • Display transcript to users
  • Trigger summarization
  • Index for search
  • Extract action items or entities

transcription.failed

Triggered when transcription processing fails.
{
  "id": "evt_jkl012",
  "type": "transcription.failed",
  "created_at": "2025-01-15T10:07:00Z",
  "data": {
    "id": "txn_abc123",
    "recording_id": "rec_xyz789",
    "status": "failed",
    "error": {
      "code": "audio_quality_insufficient",
      "message": "Audio quality is too low for accurate transcription"
    },
    "created_at": "2025-01-15T10:05:30Z",
    "failed_at": "2025-01-15T10:07:00Z"
  }
}
FieldTypeDescription
data.idstringTranscription ID
data.recording_idstringAssociated recording
data.statusstringAlways failed for this event
data.error.codestringError code
data.error.messagestringHuman-readable error message
data.failed_atstringWhen transcription failed
Error Codes:
CodeDescription
audio_quality_insufficientAudio too noisy or unclear
audio_too_shortRecording less than 1 second
audio_format_unsupportedInvalid audio format
processing_errorInternal processing error
timeoutProcessing exceeded time limit
Common Use Cases:
  • Alert users to recording issues
  • Retry with different settings
  • Log for quality monitoring

Summary Events

summary.started

Triggered when summary generation begins.
{
  "id": "evt_xyz012",
  "type": "summary.started",
  "created_at": "2025-01-15T10:07:30Z",
  "data": {
    "id": "sum_def456",
    "transcription_id": "txn_abc123",
    "recording_id": "rec_xyz789",
    "status": "processing",
    "template": "clinical",
    "created_at": "2025-01-15T10:07:20Z",
    "started_at": "2025-01-15T10:07:30Z"
  }
}
FieldTypeDescription
data.idstringSummary ID
data.transcription_idstringSource transcription
data.recording_idstringOriginal recording
data.statusstringAlways processing for this event
data.templatestringTemplate used (general, sales, clinical, legal)
data.started_atstringWhen processing started
Common Use Cases:
  • Show “generating summary” status in UI
  • Track processing time metrics
  • Update workflow progress indicators

summary.completed

Triggered when summary generation completes successfully.
{
  "id": "evt_mno345",
  "type": "summary.completed",
  "created_at": "2025-01-15T10:08:00Z",
  "data": {
    "id": "sum_def456",
    "transcription_id": "txn_abc123",
    "recording_id": "rec_xyz789",
    "status": "completed",
    "text": "The patient presented with symptoms of seasonal allergies. Dr. Smith recommended over-the-counter antihistamines and a follow-up in two weeks if symptoms persist.",
    "template": "medical_note",
    "created_at": "2025-01-15T10:07:30Z",
    "completed_at": "2025-01-15T10:08:00Z"
  }
}
FieldTypeDescription
data.idstringSummary ID
data.transcription_idstringSource transcription
data.recording_idstringOriginal recording
data.statusstringAlways completed for this event
data.textstringGenerated summary text
data.templatestringTemplate used (if specified)
data.completed_atstringWhen summary finished
Common Use Cases:
  • Display summary to users
  • Send notification that processing is complete
  • Update clinical notes or CRM records

summary.failed

Triggered when summary generation fails.
{
  "id": "evt_pqr678",
  "type": "summary.failed",
  "created_at": "2025-01-15T10:08:00Z",
  "data": {
    "id": "sum_def456",
    "transcription_id": "txn_abc123",
    "recording_id": "rec_xyz789",
    "status": "failed",
    "error": {
      "code": "content_policy_violation",
      "message": "Content could not be summarized due to policy restrictions"
    },
    "failed_at": "2025-01-15T10:08:00Z"
  }
}
FieldTypeDescription
data.error.codestringError code
data.error.messagestringHuman-readable error message

Device Events (Optional)

These events are available for enterprise customers who enable device monitoring.

device.low_battery

Triggered when device battery falls below 20%.
{
  "id": "evt_stu901",
  "type": "device.low_battery",
  "created_at": "2025-01-15T14:00:00Z",
  "data": {
    "id": "dev_device456",
    "end_user_id": "eu_user123",
    "battery_percent": 15,
    "last_sync_at": "2025-01-15T13:55:00Z"
  }
}

device.offline

Triggered when device hasn’t synced for 24+ hours.
{
  "id": "evt_vwx234",
  "type": "device.offline",
  "created_at": "2025-01-16T10:00:00Z",
  "data": {
    "id": "dev_device456",
    "end_user_id": "eu_user123",
    "last_sync_at": "2025-01-15T10:00:00Z",
    "hours_offline": 24
  }
}
Device events require enterprise plan and explicit opt-in during webhook registration.

Subscribing to Events

When creating a webhook, specify which events to receive:
curl -X POST https://api.bota.dev/v1/webhooks \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/bota",
    "events": [
      "recording.created",
      "recording.uploaded",
      "recording.deleted",
      "transcription.started",
      "transcription.completed",
      "transcription.failed",
      "summary.started",
      "summary.completed",
      "summary.failed"
    ]
  }'

Event Wildcards

Use * to subscribe to all events:
{
  "url": "https://your-app.com/webhooks/bota",
  "events": ["*"]
}
Or subscribe to all events in a category:
{
  "url": "https://your-app.com/webhooks/bota",
  "events": ["recording.*", "transcription.*"]
}

Event Delivery Order

Events are delivered in the order they occur, but network conditions may cause out-of-order arrival. Design your handlers to be order-independent. Example Timeline:
  1. recording.created — Recording entry created
  2. recording.uploaded — Audio upload completed (may be minutes/hours later)
  3. transcription.started — Transcription processing begins
  4. transcription.completed — Transcription finished
  5. summary.started — Summary generation begins
  6. summary.completed — Summary generated
Each event is independent. You may receive transcription.completed before your handler has finished processing recording.uploaded.

Handling Tips

Async Processing

Process events asynchronously to avoid timeouts:
app.post('/webhooks/bota', async (req, res) => {
  // Respond immediately
  res.status(200).send('OK');

  // Queue for async processing
  await eventQueue.add('process-webhook', req.body);
});

Type-Safe Handlers

Use TypeScript or schema validation:
type BotaEvent =
  | { type: 'recording.created'; data: RecordingCreatedData }
  | { type: 'transcription.completed'; data: TranscriptionCompletedData }
  | { type: 'summary.completed'; data: SummaryCompletedData };

function handleEvent(event: BotaEvent) {
  switch (event.type) {
    case 'recording.created':
      // event.data is typed as RecordingCreatedData
      break;
    case 'transcription.completed':
      // event.data is typed as TranscriptionCompletedData
      break;
  }
}