> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bota.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Events

> Complete reference for all Bota webhook event types and payloads

This page documents all webhook event types, their triggers, and payload schemas.

***

## Event Structure

All events follow this structure:

```json theme={null}
{
  "id": "evt_abc123def456",
  "type": "event.type",
  "created_at": "2025-01-15T10:30:00Z",
  "data": {
    // Event-specific payload
  }
}
```

| Field        | Type   | Description                                     |
| ------------ | ------ | ----------------------------------------------- |
| `id`         | string | Unique event identifier. Use for deduplication. |
| `type`       | string | Event type (e.g., `transcription.completed`)    |
| `created_at` | string | ISO 8601 timestamp of when the event occurred   |
| `data`       | object | Event-specific payload (see below)              |

***

## Recording Events

### recording.created

Triggered when a new recording is created via the API.

```json theme={null}
{
  "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"
  }
}
```

| Field                   | Type    | Description                               |
| ----------------------- | ------- | ----------------------------------------- |
| `data.id`               | string  | Recording ID                              |
| `data.end_user_id`      | string  | Associated EndUser                        |
| `data.device_id`        | string  | Device that will capture the recording    |
| `data.status`           | string  | Always `created` for this event           |
| `data.consent_obtained` | boolean | Whether consent was recorded              |
| `data.metadata`         | object  | Custom metadata attached to the recording |
| `data.created_at`       | string  | When 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.

```json theme={null}
{
  "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"
  }
}
```

| Field                   | Type    | Description                                |
| ----------------------- | ------- | ------------------------------------------ |
| `data.id`               | string  | Recording ID                               |
| `data.status`           | string  | Always `uploaded` for this event           |
| `data.duration_seconds` | number  | Audio duration in seconds                  |
| `data.file_size_bytes`  | integer | File size in bytes                         |
| `data.format`           | string  | Audio format (`wav`, `mp3`, `m4a`, `flac`) |
| `data.started_at`       | string  | When recording started (device time)       |
| `data.ended_at`         | string  | When recording ended (device time)         |
| `data.uploaded_at`      | string  | When 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.

```json theme={null}
{
  "id": "evt_rst345",
  "type": "recording.deleted",
  "created_at": "2025-01-15T11:00:00Z",
  "data": {
    "id": "rec_xyz789",
    "deleted_at": "2025-01-15T11:00:00Z"
  }
}
```

| Field             | Type   | Description                    |
| ----------------- | ------ | ------------------------------ |
| `data.id`         | string | Recording ID that was deleted  |
| `data.deleted_at` | string | When the recording was deleted |

<Note>
  When a recording is deleted, all associated transcriptions and summaries are also deleted (cascade delete).
</Note>

**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.

```json theme={null}
{
  "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"
  }
}
```

| Field               | Type   | Description                                |
| ------------------- | ------ | ------------------------------------------ |
| `data.id`           | string | Transcription ID                           |
| `data.recording_id` | string | Associated recording                       |
| `data.status`       | string | Always `processing` for this event         |
| `data.language`     | string | Language code (specified or auto-detected) |
| `data.started_at`   | string | When 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.

```json theme={null}
{
  "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"
  }
}
```

| Field                        | Type   | Description                              |
| ---------------------------- | ------ | ---------------------------------------- |
| `data.id`                    | string | Transcription ID                         |
| `data.recording_id`          | string | Associated recording                     |
| `data.status`                | string | Always `completed` for this event        |
| `data.text`                  | string | Full transcript text                     |
| `data.duration_seconds`      | number | Audio duration processed                 |
| `data.segments`              | array  | Timestamped segments with speaker labels |
| `data.segments[].start`      | number | Segment start time (seconds)             |
| `data.segments[].end`        | number | Segment end time (seconds)               |
| `data.segments[].text`       | string | Segment text                             |
| `data.segments[].speaker`    | string | Speaker identifier                       |
| `data.segments[].confidence` | number | Confidence score (0-1)                   |
| `data.speakers`              | array  | List of detected speakers                |
| `data.language`              | string | Detected language code                   |
| `data.completed_at`          | string | When 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.

```json theme={null}
{
  "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"
  }
}
```

| Field                | Type   | Description                    |
| -------------------- | ------ | ------------------------------ |
| `data.id`            | string | Transcription ID               |
| `data.recording_id`  | string | Associated recording           |
| `data.status`        | string | Always `failed` for this event |
| `data.error.code`    | string | Error code                     |
| `data.error.message` | string | Human-readable error message   |
| `data.failed_at`     | string | When transcription failed      |

**Error Codes:**

| Code                         | Description                    |
| ---------------------------- | ------------------------------ |
| `audio_quality_insufficient` | Audio too noisy or unclear     |
| `audio_too_short`            | Recording less than 1 second   |
| `audio_format_unsupported`   | Invalid audio format           |
| `processing_error`           | Internal processing error      |
| `timeout`                    | Processing 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.

```json theme={null}
{
  "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"
  }
}
```

| Field                   | Type   | Description                                             |
| ----------------------- | ------ | ------------------------------------------------------- |
| `data.id`               | string | Summary ID                                              |
| `data.transcription_id` | string | Source transcription                                    |
| `data.recording_id`     | string | Original recording                                      |
| `data.status`           | string | Always `processing` for this event                      |
| `data.template`         | string | Template used (`general`, `sales`, `clinical`, `legal`) |
| `data.started_at`       | string | When 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.

```json theme={null}
{
  "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"
  }
}
```

| Field                   | Type   | Description                       |
| ----------------------- | ------ | --------------------------------- |
| `data.id`               | string | Summary ID                        |
| `data.transcription_id` | string | Source transcription              |
| `data.recording_id`     | string | Original recording                |
| `data.status`           | string | Always `completed` for this event |
| `data.text`             | string | Generated summary text            |
| `data.template`         | string | Template used (if specified)      |
| `data.completed_at`     | string | When 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.

```json theme={null}
{
  "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"
  }
}
```

| Field                | Type   | Description                  |
| -------------------- | ------ | ---------------------------- |
| `data.error.code`    | string | Error code                   |
| `data.error.message` | string | Human-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%.

```json theme={null}
{
  "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.

```json theme={null}
{
  "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
  }
}
```

<Note>
  Device events require enterprise plan and explicit opt-in during webhook registration.
</Note>

***

## Subscribing to Events

When creating a webhook, specify which events to receive:

```bash theme={null}
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:

```json theme={null}
{
  "url": "https://your-app.com/webhooks/bota",
  "events": ["*"]
}
```

Or subscribe to all events in a category:

```json theme={null}
{
  "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:

```javascript theme={null}
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:

```typescript theme={null}
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;
  }
}
```

***

## Related

<CardGroup cols={2}>
  <Card title="Webhooks Overview" icon="bell" href="/webhooks/overview">
    Setup, verification, and best practices
  </Card>

  <Card title="Create Webhook" icon="plus" href="/api-reference/webhooks/create">
    API endpoint reference
  </Card>
</CardGroup>
