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

# Send SMS

> Send an SMS message through an assistant.

This endpoint allows sending SMS messages using the telephony provider
associated with the assistant that owns the from_phone_number.

The system will automatically:
1. Find the assistant associated with the from_phone_number
2. Use the assistant's configured telephony provider (Twilio, Telnyx, or Vonage)
3. Queue the SMS for delivery with per-provider rate limiting (default)
   or send immediately if queue=False
4. Persist the outbound message to the SMS conversation (ChatMessage) for UI display

Idempotency:
    Pass an Idempotency-Key header (or idempotency_key in body) to dedupe sends
    from retried requests. Format: e.g., "chat:123:msg:456:outbound"

Args:
    sms_data: SMS request containing from/to numbers, message, and queue option

Returns:
    SendSMSResponse: Success status, message ID, status, and provider info

This endpoint allows you to send SMS messages through one of your AI assistants. The system automatically determines which telephony provider (Twilio, Telnyx, or Vonage) to use based on the assistant configuration associated with the `from_phone_number`.

## How It Works

1. **Assistant Lookup**: The system identifies the assistant based on the `from_phone_number`
2. **Provider Selection**: Automatically uses the assistant's configured telephony provider
3. **Queue or Send**: Either queues the message (with rate limiting) or sends immediately
4. **Response**: Returns success status with message ID, provider, and delivery status

<Info>
  **Multi-Provider Support**: Your assistants can use different telephony providers. The system automatically routes SMS messages through the correct provider based on which assistant owns the phone number.
</Info>

## Request Body

| Parameter           | Type    | Required | Description                                                                 |
| ------------------- | ------- | -------- | --------------------------------------------------------------------------- |
| `from_phone_number` | string  | Yes      | Sender phone number (must be assigned to an assistant)                      |
| `to_phone_number`   | string  | Yes      | Recipient phone number in E.164 format                                      |
| `message`           | string  | Yes      | SMS message content (max 1600 characters)                                   |
| `media_urls`        | array   | No       | List of media URLs for MMS messages                                         |
| `queue`             | boolean | No       | If `true` (default), queue with rate limiting. If `false`, send immediately |
| `idempotency_key`   | string  | No       | Unique key to prevent duplicate sends on retries (max 256 chars)            |

### Basic Request

```json theme={null}
{
  "from_phone_number": "+1234567890",
  "to_phone_number": "+1555123456",
  "message": "Hello! This is a follow-up message from your AI assistant."
}
```

### With All Options

```json theme={null}
{
  "from_phone_number": "+1234567890",
  "to_phone_number": "+1555123456",
  "message": "Hello! This is a follow-up message from your AI assistant.",
  "media_urls": ["https://example.com/image.jpg"],
  "queue": false,
  "idempotency_key": "order:12345:confirmation"
}
```

## Queue vs Immediate Send

<Tabs>
  <Tab title="Queued (Default)">
    When `queue: true` (default):

    * Messages are queued and sent with rate limiting
    * Helps avoid carrier throttling
    * Better for bulk sends
    * Returns `status: "queued"`

    ```json theme={null}
    {
      "queue": true
    }
    ```
  </Tab>

  <Tab title="Immediate">
    When `queue: false`:

    * Message is sent immediately
    * Better for time-sensitive messages
    * May hit rate limits if sending many messages
    * Returns `status: "sent"` on success; provider failures return an error response instead of a successful `failed` response

    ```json theme={null}
    {
      "queue": false
    }
    ```
  </Tab>
</Tabs>

## Idempotency

The `idempotency_key` parameter prevents duplicate messages when retrying failed requests:

```json theme={null}
{
  "from_phone_number": "+1234567890",
  "to_phone_number": "+1555123456",
  "message": "Your order #12345 has shipped!",
  "idempotency_key": "order:12345:shipped:notification"
}
```

<Info>
  **Header Alternative**: You can also provide the idempotency key via the `Idempotency-Key` header. If both are provided, the header takes precedence.
</Info>

## Response

A successful request returns a `200 OK` status with details about the message.

```json theme={null}
{
  "success": true,
  "message_id": "8ad70ee5-3d47-4fa4-a6ab-c9f2238d5f54",
  "message": "SMS queued successfully via telnyx",
  "provider": "telnyx",
  "status": "queued"
}
```

## Response Fields

| Field        | Type    | Description                                               |
| ------------ | ------- | --------------------------------------------------------- |
| `success`    | boolean | Whether the operation was successful                      |
| `message_id` | string  | Unique identifier for the message                         |
| `message`    | string  | Human-readable status message                             |
| `provider`   | string  | Telephony provider used (`twilio`, `telnyx`, or `vonage`) |
| `status`     | string  | Delivery status: `queued`, `sent`, or `failed`            |

For queued messages, `message_id` is Burki's queue UUID. After delivery, use the status endpoint to inspect the provider's message ID when available.

## Error Responses

### 400 Bad Request

Returned when the request is malformed or contains invalid data.

```json theme={null}
{
  "detail": "Invalid to_phone_number format. Use E.164 format (e.g., +1234567890)"
}
```

Common causes:

* Missing required fields (`from_phone_number`, `to_phone_number`, `message`)
* Invalid phone number format (must be E.164)
* Empty message content
* Message exceeds 1600 characters

### 403 Forbidden

Returned when the authenticated user does not own the assistant or phone number used as `from_phone_number`.

```json theme={null}
{
  "detail": "Unauthorized: phone number belongs to different organization"
}
```

### 404 Not Found

Returned when no assistant is found for the specified `from_phone_number`.

```json theme={null}
{
  "detail": "No assistant found for phone number +1234567890"
}
```

### 500 Internal Server Error

Returned when the telephony provider fails to send the message.

```json theme={null}
{
  "detail": "Failed to send SMS via telnyx"
}
```

## Use Cases

### Customer Service Follow-up

Send follow-up messages after customer service calls:

```json theme={null}
{
  "from_phone_number": "+1234567890",
  "to_phone_number": "+1555123456",
  "message": "Thanks for calling! Here's the link we discussed: https://support.example.com/article/123",
  "queue": false
}
```

### Appointment Reminders

Send automated appointment reminders with idempotency:

```json theme={null}
{
  "from_phone_number": "+1234567890",
  "to_phone_number": "+1555123456",
  "message": "Reminder: Your appointment is tomorrow at 2:00 PM. Reply CONFIRM to confirm or RESCHEDULE to change the time.",
  "idempotency_key": "appointment:456:reminder:24h"
}
```

### Bulk Notifications (Queued)

For sending many messages, use the queue to avoid rate limits:

```json theme={null}
{
  "from_phone_number": "+1234567890",
  "to_phone_number": "+1555123456",
  "message": "Flash sale! 50% off all items today only. Shop now: example.com/sale",
  "queue": true
}
```

### Document Sharing (MMS)

Send documents or images via MMS:

```json theme={null}
{
  "from_phone_number": "+1234567890",
  "to_phone_number": "+1555123456",
  "message": "Here are the documents you requested:",
  "media_urls": [
    "https://yourdomain.com/documents/contract.pdf",
    "https://yourdomain.com/images/diagram.png"
  ]
}
```

## Authentication

This endpoint requires authentication. Include your API key in the request headers:

```bash theme={null}
curl -X POST "https://api.burki.dev/sms/send" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from_phone_number": "+1234567890",
    "to_phone_number": "+1555123456",
    "message": "Hello from your AI assistant!"
  }'
```

## Related Endpoints

| Method   | Path                       | Purpose                                         |
| -------- | -------------------------- | ----------------------------------------------- |
| `GET`    | `/sms/{message_id}/status` | Check queued, sent, failed, or cancelled status |
| `DELETE` | `/sms/{message_id}`        | Cancel a queued message before delivery         |
| `GET`    | `/sms/queue/stats`         | Inspect queue statistics by provider            |

## Rate Limits

SMS sending is subject to rate limits imposed by the underlying telephony providers:

* **Twilio**: Varies by account type and message volume
* **Telnyx**: Varies by account configuration
* **Vonage**: Varies by account type

<Warning>
  **Provider Limits**: Each telephony provider has its own rate limits and restrictions. Use the `queue: true` option (default) to let Burki handle rate limiting automatically.
</Warning>

## Best Practices

### Phone Number Format

Always use E.164 format for phone numbers:

* Correct: `+1234567890`
* Incorrect: `(123) 456-7890`, `123-456-7890`, `1234567890`

### Idempotency Keys

Use meaningful idempotency keys that include:

* The type of message (e.g., `order`, `appointment`, `alert`)
* A unique identifier (e.g., order ID, appointment ID)
* The specific action (e.g., `confirmation`, `reminder`)

Examples:

* `order:12345:confirmation`
* `appointment:789:reminder:24h`
* `chat:session123:msg:456:outbound`

### Message Content

* Keep messages concise and clear
* Include clear call-to-action when needed
* Respect opt-out requests and regulatory requirements
* Consider character limits for international SMS

### Error Handling

Always handle potential errors in your code:

```python theme={null}
import requests

response = requests.post(
    "https://api.burki.dev/sms/send",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "from_phone_number": "+1234567890",
        "to_phone_number": "+1555123456",
        "message": "Hello from your AI assistant!",
        "idempotency_key": "test:123:hello"
    }
)

if response.status_code == 200:
    data = response.json()
    print(f"SMS {data['status']} via {data['provider']}")
    print(f"Message ID: {data['message_id']}")
else:
    print(f"Error: {response.status_code} - {response.json()['detail']}")
```

## Integration Examples

### Node.js

```javascript theme={null}
const axios = require('axios');

async function sendSMS(fromPhone, toPhone, message, options = {}) {
  try {
    const response = await axios.post('https://api.burki.dev/sms/send', {
      from_phone_number: fromPhone,
      to_phone_number: toPhone,
      message: message,
      queue: options.queue ?? true,
      idempotency_key: options.idempotencyKey
    }, {
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
      }
    });
    
    console.log(`SMS ${response.data.status}:`, response.data);
    return response.data;
  } catch (error) {
    console.error('Failed to send SMS:', error.response.data);
    throw error;
  }
}

// Usage
sendSMS('+1234567890', '+1555123456', 'Hello!', {
  queue: false,
  idempotencyKey: 'test:123'
});
```

### Python

```python theme={null}
import requests

def send_sms(from_phone, to_phone, message, media_urls=None, queue=True, idempotency_key=None):
    url = "https://api.burki.dev/sms/send"
    headers = {
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json"
    }
    
    payload = {
        "from_phone_number": from_phone,
        "to_phone_number": to_phone,
        "message": message,
        "queue": queue
    }
    
    if media_urls:
        payload["media_urls"] = media_urls
    
    if idempotency_key:
        payload["idempotency_key"] = idempotency_key
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"SMS failed: {response.json()['detail']}")

# Usage
result = send_sms(
    "+1234567890",
    "+1555123456",
    "Your order has shipped!",
    idempotency_key="order:789:shipped"
)
print(f"Status: {result['status']}")
```

### PHP

```php theme={null}
<?php
function sendSMS($fromPhone, $toPhone, $message, $options = []) {
    $url = 'https://api.burki.dev/sms/send';
    $headers = [
        'Authorization: Bearer YOUR_API_KEY',
        'Content-Type: application/json'
    ];
    
    $data = [
        'from_phone_number' => $fromPhone,
        'to_phone_number' => $toPhone,
        'message' => $message,
        'queue' => $options['queue'] ?? true
    ];
    
    if (isset($options['media_urls'])) {
        $data['media_urls'] = $options['media_urls'];
    }
    
    if (isset($options['idempotency_key'])) {
        $data['idempotency_key'] = $options['idempotency_key'];
    }
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode === 200) {
        return json_decode($response, true);
    } else {
        throw new Exception("SMS failed: " . $response);
    }
}
?>
```


## OpenAPI

````yaml POST /sms/send
openapi: 3.1.0
info:
  title: Burki
  description: A system that uses AI to answer customer Calls.
  version: 0.1.0
servers: []
security: []
paths:
  /sms/send:
    post:
      summary: Send Sms
      description: >-
        Send an SMS message through an assistant.


        This endpoint allows sending SMS messages using the telephony provider

        associated with the assistant that owns the from_phone_number.


        The system will automatically:

        1. Find the assistant associated with the from_phone_number

        2. Use the assistant's configured telephony provider (Twilio, Telnyx, or
        Vonage)

        3. Queue the SMS for delivery with per-provider rate limiting (default)
           or send immediately if queue=False
        4. Persist the outbound message to the SMS conversation (ChatMessage)
        for UI display


        Idempotency:
            Pass an Idempotency-Key header (or idempotency_key in body) to dedupe sends
            from retried requests. Format: e.g., "chat:123:msg:456:outbound"

        Args:
            sms_data: SMS request containing from/to numbers, message, and queue option

        Returns:
            SendSMSResponse: Success status, message ID, status, and provider info
      operationId: send_sms_sms_send_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendSMSRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendSMSResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - HTTPBearer: []
components:
  schemas:
    SendSMSRequest:
      properties:
        from_phone_number:
          type: string
          title: From Phone Number
          description: Sender phone number (must be assigned to an assistant)
        to_phone_number:
          type: string
          title: To Phone Number
          description: Recipient phone number in E.164 format (e.g., +1234567890)
        message:
          type: string
          maxLength: 1600
          title: Message
          description: SMS message content
        media_urls:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Media Urls
          description: Optional list of media URLs for MMS
        queue:
          type: boolean
          title: Queue
          description: >-
            If True (default), queue the SMS with rate limiting. If False, send
            immediately.
          default: true
        idempotency_key:
          anyOf:
            - type: string
              maxLength: 256
            - type: 'null'
          title: Idempotency Key
          description: >-
            Optional idempotency key (e.g., 'chat:123:msg:456:outbound'). If
            provided, Burki will dedupe based on this key to prevent duplicate
            sends/persistence on retries. Can also be provided via
            Idempotency-Key header (header takes precedence).
      type: object
      required:
        - from_phone_number
        - to_phone_number
        - message
      title: SendSMSRequest
      description: Request model for sending SMS through an assistant.
    SendSMSResponse:
      properties:
        success:
          type: boolean
          title: Success
        message_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Message Id
        message:
          type: string
          title: Message
        provider:
          anyOf:
            - type: string
            - type: 'null'
          title: Provider
        status:
          anyOf:
            - type: string
            - type: 'null'
          title: Status
          description: 'Message status: ''queued'', ''sent'', ''failed'''
      type: object
      required:
        - success
        - message
      title: SendSMSResponse
      description: Response model for send SMS endpoint.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````