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

# Quickstart

> Get up and running with the Bota API in minutes

This guide walks you through the complete flow: creating an end user, registering a device, uploading audio, and getting a transcript. By the end, you'll understand how to integrate Bota into your application.

## Prerequisites

<Check>A Bota account with API access — [Sign up here](https://platform.bota.dev)</Check>
<Check>Your project API key from the dashboard</Check>

You'll need your **API key** (`sk_live_...`) from the dashboard.

## Step 1: Create an End User

End users represent the people who wear your devices. They don't log into Bota — they exist in your project to associate recordings with the right person.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/end-users \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "external_id": "user_123",
      "name": "John Doe",
      "email": "john@example.com"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.bota.dev/v1/end-users', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_live_...',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      external_id: 'user_123',
      name: 'John Doe',
      email: 'john@example.com',
    }),
  });

  const endUser = await response.json();
  console.log(endUser.id); // eu_abc123
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://api.bota.dev/v1/end-users',
      headers={
          'Authorization': 'Bearer sk_live_...',
          'Content-Type': 'application/json',
      },
      json={
          'external_id': 'user_123',
          'name': 'John Doe',
          'email': 'john@example.com',
      },
  )

  end_user = response.json()
  print(end_user['id'])  # eu_abc123
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "id": "eu_abc123",
  "external_id": "user_123",
  "name": "John Doe",
  "email": "john@example.com",
  "created_at": "2025-01-15T10:00:00Z"
}
```

<Info>
  The `external_id` lets you link Bota end users to users in your system. Store a mapping between `external_id` and the Bota `id` for lookups.
</Info>

## Step 2: Register a Device

Register the wearable device using its serial number. The serial number is printed on the device or packaging.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/devices \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "serial_number": "SN-2025-001234",
      "device_type": "bota_pin_v1"
    }'
  ```

  ```javascript Node.js theme={null}
  const device = await fetch('https://api.bota.dev/v1/devices', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_live_...',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      serial_number: 'SN-2025-001234',
      device_type: 'bota_pin_v1',
    }),
  }).then(r => r.json());

  console.log(device.id); // dev_xyz789
  ```

  ```python Python theme={null}
  device = requests.post(
      'https://api.bota.dev/v1/devices',
      headers={
          'Authorization': 'Bearer sk_live_...',
          'Content-Type': 'application/json',
      },
      json={
          'serial_number': 'SN-2025-001234',
          'device_type': 'bota_pin_v1',
      },
  ).json()

  print(device['id'])  # dev_xyz789
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "id": "dev_xyz789",
  "serial_number": "SN-2025-001234",
  "device_type": "bota_pin_v1",
  "status": "unbound",
  "end_user_id": null,
  "created_at": "2025-01-15T10:01:00Z"
}
```

## Step 3: Bind Device to User

Associate the device with the end user. A device can only be bound to one user at a time.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/devices/dev_xyz789/bind \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "end_user_id": "eu_abc123"
    }'
  ```

  ```javascript Node.js theme={null}
  await fetch('https://api.bota.dev/v1/devices/dev_xyz789/bind', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_live_...',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      end_user_id: 'eu_abc123',
    }),
  });
  ```

  ```python Python theme={null}
  requests.post(
      'https://api.bota.dev/v1/devices/dev_xyz789/bind',
      headers={
          'Authorization': 'Bearer sk_live_...',
          'Content-Type': 'application/json',
      },
      json={
          'end_user_id': 'eu_abc123',
      },
  )
  ```
</CodeGroup>

The device status changes from `unbound` to `bound`, and all future recordings are automatically associated with this end user.

## Step 4: Create a Recording

When the device captures audio, create a recording entry in Bota. This returns a recording ID you'll use for upload and transcription.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/recordings \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "device_id": "dev_xyz789",
      "started_at": "2025-01-15T09:00:00Z",
      "ended_at": "2025-01-15T09:30:00Z",
      "metadata": {
        "meeting_type": "client_call",
        "location": "office"
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const recording = await fetch('https://api.bota.dev/v1/recordings', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_live_...',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      device_id: 'dev_xyz789',
      started_at: '2025-01-15T09:00:00Z',
      ended_at: '2025-01-15T09:30:00Z',
      metadata: {
        meeting_type: 'client_call',
        location: 'office',
      },
    }),
  }).then(r => r.json());

  console.log(recording.id); // rec_abc123
  ```

  ```python Python theme={null}
  recording = requests.post(
      'https://api.bota.dev/v1/recordings',
      headers={
          'Authorization': 'Bearer sk_live_...',
          'Content-Type': 'application/json',
      },
      json={
          'device_id': 'dev_xyz789',
          'started_at': '2025-01-15T09:00:00Z',
          'ended_at': '2025-01-15T09:30:00Z',
          'metadata': {
              'meeting_type': 'client_call',
              'location': 'office',
          },
      },
  ).json()

  print(recording['id'])  # rec_abc123
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "id": "rec_abc123",
  "device_id": "dev_xyz789",
  "end_user_id": "eu_abc123",
  "status": "pending",
  "metadata": {
    "meeting_type": "client_call",
    "location": "office"
  },
  "created_at": "2025-01-15T10:05:00Z"
}
```

## Step 5: Upload Audio

Upload audio in three steps: get a pre-signed URL, upload the file, then mark complete.

### 5a. Get Upload URL

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/recordings/rec_abc123/upload-url \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "content_type": "audio/wav"
    }'
  ```

  ```javascript Node.js theme={null}
  const { upload_url, headers } = await fetch(
    'https://api.bota.dev/v1/recordings/rec_abc123/upload-url',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer sk_live_...',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ content_type: 'audio/wav' }),
    }
  ).then(r => r.json());
  ```

  ```python Python theme={null}
  upload_info = requests.post(
      'https://api.bota.dev/v1/recordings/rec_abc123/upload-url',
      headers={
          'Authorization': 'Bearer sk_live_...',
          'Content-Type': 'application/json',
      },
      json={'content_type': 'audio/wav'},
  ).json()

  upload_url = upload_info['upload_url']
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "upload_url": "https://bota-uploads.s3.amazonaws.com/...",
  "expires_at": "2025-01-15T11:05:00Z",
  "headers": {
    "Content-Type": "audio/wav"
  }
}
```

### 5b. Upload to S3

Upload directly to the pre-signed URL. This bypasses the Bota API for faster uploads.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT "https://bota-uploads.s3.amazonaws.com/..." \
    -H "Content-Type: audio/wav" \
    --data-binary @recording.wav
  ```

  ```javascript Node.js theme={null}
  await fetch(upload_url, {
    method: 'PUT',
    headers: { 'Content-Type': 'audio/wav' },
    body: audioBuffer,
  });
  ```

  ```python Python theme={null}
  with open('recording.wav', 'rb') as f:
      requests.put(
          upload_url,
          headers={'Content-Type': 'audio/wav'},
          data=f.read(),
      )
  ```
</CodeGroup>

### 5c. Mark Upload Complete

Tell Bota the upload finished. This triggers validation and updates the recording status.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/recordings/rec_abc123/upload-complete \
    -H "Authorization: Bearer sk_live_..."
  ```

  ```javascript Node.js theme={null}
  await fetch('https://api.bota.dev/v1/recordings/rec_abc123/upload-complete', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer sk_live_...' },
  });
  ```

  ```python Python theme={null}
  requests.post(
      'https://api.bota.dev/v1/recordings/rec_abc123/upload-complete',
      headers={'Authorization': 'Bearer sk_live_...'},
  )
  ```
</CodeGroup>

The recording status changes from `pending` to `uploaded`.

## Step 6: Transcribe

Start an async transcription job. Transcription typically takes 10-30% of the audio duration.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/recordings/rec_abc123/transcribe \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "language": "en",
      "diarization": true
    }'
  ```

  ```javascript Node.js theme={null}
  const transcription = await fetch(
    'https://api.bota.dev/v1/recordings/rec_abc123/transcribe',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer sk_live_...',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ language: 'en', diarization: true }),
    }
  ).then(r => r.json());

  console.log(transcription.id); // txn_def456
  ```

  ```python Python theme={null}
  transcription = requests.post(
      'https://api.bota.dev/v1/recordings/rec_abc123/transcribe',
      headers={
          'Authorization': 'Bearer sk_live_...',
          'Content-Type': 'application/json',
      },
      json={'language': 'en', 'diarization': True},
  ).json()

  print(transcription['id'])  # txn_def456
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "id": "txn_def456",
  "recording_id": "rec_abc123",
  "status": "pending",
  "language": "en",
  "created_at": "2025-01-15T10:10:00Z"
}
```

## Step 7: Get Results

Poll the transcription endpoint until status is `completed`, or use webhooks for real-time notifications.

### Option A: Polling

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.bota.dev/v1/transcriptions/txn_def456 \
    -H "Authorization: Bearer sk_live_..."
  ```

  ```javascript Node.js theme={null}
  async function waitForTranscription(id) {
    while (true) {
      const result = await fetch(
        `https://api.bota.dev/v1/transcriptions/${id}`,
        { headers: { 'Authorization': 'Bearer sk_live_...' } }
      ).then(r => r.json());

      if (result.status === 'completed') return result;
      if (result.status === 'failed') throw new Error(result.error.message);

      await new Promise(r => setTimeout(r, 2000)); // Wait 2 seconds
    }
  }

  const transcript = await waitForTranscription('txn_def456');
  ```

  ```python Python theme={null}
  import time

  def wait_for_transcription(transcription_id):
      while True:
          result = requests.get(
              f'https://api.bota.dev/v1/transcriptions/{transcription_id}',
              headers={'Authorization': 'Bearer sk_live_...'},
          ).json()

          if result['status'] == 'completed':
              return result
          if result['status'] == 'failed':
              raise Exception(result['error']['message'])

          time.sleep(2)

  transcript = wait_for_transcription('txn_def456')
  ```
</CodeGroup>

### Option B: Webhooks (Recommended)

Configure a webhook endpoint to receive notifications when transcription completes. See the [Webhooks Guide](/api-reference/webhooks/overview) for setup instructions.

```json theme={null}
// Webhook payload
{
  "id": "evt_abc123",
  "type": "transcription.completed",
  "created_at": "2025-01-15T10:15:00Z",
  "data": {
    "id": "txn_def456",
    "recording_id": "rec_abc123",
    "status": "completed",
    "text": "Hello, thanks for joining us today...",
    "segments": [...]
  }
}
```

### Transcription Result

```json theme={null}
{
  "id": "txn_def456",
  "recording_id": "rec_abc123",
  "status": "completed",
  "language": "en",
  "duration_ms": 1800000,
  "text": "Hello, thanks for joining us today. Happy to be here! So let's discuss the project timeline...",
  "segments": [
    {
      "text": "Hello, thanks for joining us today.",
      "speaker": "SPEAKER_0",
      "start": 0.0,
      "end": 2.5,
      "confidence": 0.97
    },
    {
      "text": "Happy to be here!",
      "speaker": "SPEAKER_1",
      "start": 2.8,
      "end": 4.2,
      "confidence": 0.95
    },
    {
      "text": "So let's discuss the project timeline...",
      "speaker": "SPEAKER_0",
      "start": 4.5,
      "end": 7.1,
      "confidence": 0.94
    }
  ],
  "created_at": "2025-01-15T10:10:00Z",
  "completed_at": "2025-01-15T10:15:00Z"
}
```

## Common Integration Patterns

<AccordionGroup>
  <Accordion title="Mobile App Integration">
    Your mobile app handles Bluetooth pairing and audio sync using our SDK. Your backend handles Bota API calls.

    1. User logs into your app (your auth)
    2. App pairs with device via Bluetooth using the [React Native SDK](https://github.com/bota-dev/react-native-sdk)
    3. App requests upload URL from your backend
    4. Your backend calls Bota API with secret key
    5. SDK uploads audio directly to S3 with retry logic
    6. Your backend triggers transcription
    7. Webhook notifies your backend when complete

    See the [examples repository](https://github.com/bota-dev/examples) for a complete React Native app.
  </Accordion>

  <Accordion title="Lazy vs Eager EndUser Creation">
    **Lazy (Recommended):** Create Bota EndUser on first device pairing. Simpler, no unused records.

    **Eager:** Create Bota EndUser at signup. Faster first device pairing, but requires cleanup if user never pairs.
  </Accordion>

  <Accordion title="Handling Device Reassignment">
    When a user leaves or device changes hands:

    1. Unbind the device: `POST /devices/{id}/unbind`
    2. Optionally delete old recordings
    3. Bind to new user: `POST /devices/{id}/bind`

    Device tokens are automatically rotated on unbind.
  </Accordion>
</AccordionGroup>

## What's Next?

<CardGroup cols={2}>
  <Card title="Client SDKs" icon="mobile" href="/api-reference/client-sdks">
    React Native SDK for mobile app integration
  </Card>

  <Card title="Set Up Webhooks" icon="bell" href="/webhooks/overview">
    Get real-time notifications instead of polling
  </Card>

  <Card title="Authentication Deep Dive" icon="key" href="/authentication">
    Learn about API key types and security best practices
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Explore the complete API documentation
  </Card>
</CardGroup>
