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

# Toast Notification API

> HTTP REST API for external toast notifications

# Toast Notification API

The Toast Notification API is a lightweight HTTP REST server that allows external applications to send toast notifications to your Mixlar device.

## Base URL

```
http://localhost:8889
```

### Network Access Options

* **Local**: `http://localhost:8889` (this computer only)
* **Local Network**: `http://[YOUR-LOCAL-IP]:8889` (e.g., `http://192.168.1.100:8889`)
* **Tailscale**: `http://[TAILSCALE-IP]:8889` or `https://[HOSTNAME]:8889` (with certificates)

To get all available network addresses:

```bash theme={null}
GET /api/toast/network
```

## Authentication

All endpoints (except `/health`) require API key authentication.

### Methods

**Header Authentication (Recommended)**

```http theme={null}
X-API-Key: your-api-key-here
```

**Query Parameter Authentication**

```http theme={null}
?api_key=your-api-key-here
```

### Getting Your API Key

The API key is automatically generated on first startup and stored in `mixer_config.json` under the key `toast_api_key`. You can also:

1. Check the console output when the server starts
2. Use the Toast Settings UI in the desktop app
3. Call `POST /api/toast/regenerate` to generate a new key

## Rate Limiting

* **Limit**: 30 requests per minute per IP address
* **Window**: 60 seconds rolling window
* **Response**: HTTP 429 Too Many Requests

```json theme={null}
{
  "error": "Rate limited",
  "message": "Too many requests"
}
```

## Endpoints

### Health Check

Check if the API server is running.

```http theme={null}
GET /api/toast/health
```

**Authentication**: Not required

**Response**: `200 OK`

```json theme={null}
{
  "status": "ok",
  "version": "1.0",
  "port": 8889
}
```

***

### Send Toast Notification

Send a toast notification to the device.

```http theme={null}
POST /api/toast/send
```

**Authentication**: Required

**Request Body**:

```json theme={null}
{
  "message": "Build Complete!",
  "icon": "checkmark",
  "subtitle": "webpack compiled successfully",
  "duration_ms": 5000,
  "color": "00FF00"
}
```

**Parameters**:

| Field         | Type    | Required | Description                      | Constraints                |
| ------------- | ------- | -------- | -------------------------------- | -------------------------- |
| `message`     | string  | Yes      | Header text displayed in bold    | Max 30 characters          |
| `icon`        | string  | No       | Icon name (see below)            | Default: `"bell"`          |
| `subtitle`    | string  | No       | Subtitle text displayed below    | Max 40 characters          |
| `duration_ms` | integer | No       | Display duration in milliseconds | 1000-30000, default: 3000  |
| `color`       | string  | No       | Background color (hex)           | With or without `#` prefix |

**Available Icons**:

* `bell` - Notification bell
* `checkmark` - Success checkmark
* `warning` - Warning triangle
* `close` - Error/close X
* `settings` - Gear icon
* `wifi` - WiFi signal
* `audio` - Speaker icon
* `play` - Play button
* `pause` - Pause button
* `volume` - Volume icon
* `mute` - Mute icon
* `power` - Power button
* `refresh` - Refresh/reload
* `home` - Home icon
* `download` - Download arrow
* `upload` - Upload arrow

**Response**: `200 OK`

```json theme={null}
{
  "status": "success",
  "message": "Toast notification sent"
}
```

**Error Responses**:

`400 Bad Request` - Missing required fields

```json theme={null}
{
  "error": "Bad request",
  "message": "message field is required"
}
```

`401 Unauthorized` - Invalid API key

```json theme={null}
{
  "error": "Unauthorized",
  "message": "Invalid API key"
}
```

`429 Too Many Requests` - Rate limit exceeded

```json theme={null}
{
  "error": "Rate limited",
  "message": "Too many requests"
}
```

***

### List Toast Handlers

Get a list of all available toast handlers and their status.

```http theme={null}
GET /api/toast/handlers
```

**Authentication**: Required

**Response**: `200 OK`

```json theme={null}
{
  "status": "success",
  "handlers": [
    {
      "id": "obs",
      "name": "OBS Studio",
      "enabled": true,
      "loaded": true,
      "color": "#9147FF"
    },
    {
      "id": "spotify",
      "name": "Spotify",
      "enabled": true,
      "loaded": false,
      "color": "#1DB954"
    }
  ]
}
```

***

### Get Server Status

Get information about the API server and device connection.

```http theme={null}
GET /api/toast/status
```

**Authentication**: Required

**Response**: `200 OK`

```json theme={null}
{
  "status": "success",
  "server_running": true,
  "device_connected": true,
  "port": 8889,
  "rate_limit": {
    "window_seconds": 60,
    "max_requests": 30
  }
}
```

***

### Get Network Information

Get all available network addresses and Tailscale status.

```http theme={null}
GET /api/toast/network
```

**Authentication**: Required

**Response**: `200 OK`

```json theme={null}
{
  "status": "success",
  "addresses": [
    {
      "ip": "localhost",
      "url": "http://localhost:8889",
      "type": "This Computer"
    },
    {
      "ip": "100.64.1.2",
      "url": "https://mydevice.tailnet.ts.net:8889",
      "type": "Tailscale (HTTPS - Secure Remote Access)",
      "tailscale": true,
      "https": true
    },
    {
      "ip": "192.168.1.100",
      "url": "http://192.168.1.100:8889",
      "type": "Local Network"
    }
  ],
  "tailscale": {
    "installed": true,
    "running": true,
    "ip": "100.64.1.2",
    "hostname": "mydevice.tailnet.ts.net"
  },
  "recommended": "tailscale"
}
```

***

## Example Usage

### cURL

**Basic Example**:

```bash theme={null}
curl -X POST http://localhost:8889/api/toast/send \
  -H "X-API-Key: YOUR_API_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Test Notification",
    "icon": "bell",
    "subtitle": "From API",
    "duration_ms": 5000,
    "color": "FF5733"
  }'
```

**Success Notification**:

```bash theme={null}
curl -X POST http://localhost:8889/api/toast/send \
  -H "X-API-Key: YOUR_API_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Build Complete!",
    "icon": "checkmark",
    "color": "00FF00"
  }'
```

**Error Notification**:

```bash theme={null}
curl -X POST http://localhost:8889/api/toast/send \
  -H "X-API-Key: YOUR_API_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Build Failed",
    "icon": "close",
    "subtitle": "Check console for errors",
    "duration_ms": 10000,
    "color": "FF0000"
  }'
```

### Python

```python theme={null}
import requests

API_KEY = "YOUR_API_KEY_HERE"
BASE_URL = "http://localhost:8889"

def send_toast(message, icon="bell", subtitle=None, duration_ms=3000, color=None):
    """Send a toast notification."""
    url = f"{BASE_URL}/api/toast/send"
    headers = {
        "X-API-Key": API_KEY,
        "Content-Type": "application/json"
    }

    payload = {
        "message": message,
        "icon": icon
    }

    if subtitle:
        payload["subtitle"] = subtitle
    if duration_ms:
        payload["duration_ms"] = duration_ms
    if color:
        payload["color"] = color

    response = requests.post(url, json=payload, headers=headers)
    return response.json()

# Examples
send_toast("Server Started", icon="checkmark", color="00FF00")
send_toast("New Email", icon="bell", subtitle="From: john@example.com")
send_toast("Critical Error", icon="warning", color="FF0000", duration_ms=10000)
```

### JavaScript / Node.js

```javascript theme={null}
const axios = require('axios');

const API_KEY = 'YOUR_API_KEY_HERE';
const BASE_URL = 'http://localhost:8889';

async function sendToast(message, options = {}) {
  const {
    icon = 'bell',
    subtitle = null,
    duration_ms = 3000,
    color = null
  } = options;

  const payload = { message, icon };
  if (subtitle) payload.subtitle = subtitle;
  if (duration_ms) payload.duration_ms = duration_ms;
  if (color) payload.color = color;

  try {
    const response = await axios.post(`${BASE_URL}/api/toast/send`, payload, {
      headers: {
        'X-API-Key': API_KEY,
        'Content-Type': 'application/json'
      }
    });
    return response.data;
  } catch (error) {
    console.error('Toast error:', error.response?.data || error.message);
    throw error;
  }
}

// Examples
await sendToast('Deployment Complete', { icon: 'checkmark', color: '00FF00' });
await sendToast('Test Failed', {
  icon: 'close',
  subtitle: 'Unit tests: 15 failed',
  color: 'FF0000',
  duration_ms: 8000
});
```

### PowerShell

```powershell theme={null}
$apiKey = "YOUR_API_KEY_HERE"
$baseUrl = "http://localhost:8889"

function Send-Toast {
    param(
        [string]$Message,
        [string]$Icon = "bell",
        [string]$Subtitle,
        [int]$DurationMs = 3000,
        [string]$Color
    )

    $headers = @{
        "X-API-Key" = $apiKey
        "Content-Type" = "application/json"
    }

    $body = @{
        message = $Message
        icon = $Icon
    }

    if ($Subtitle) { $body.subtitle = $Subtitle }
    if ($DurationMs) { $body.duration_ms = $DurationMs }
    if ($Color) { $body.color = $Color }

    $json = $body | ConvertTo-Json

    Invoke-RestMethod -Uri "$baseUrl/api/toast/send" `
        -Method Post `
        -Headers $headers `
        -Body $json
}

# Examples
Send-Toast -Message "Backup Complete" -Icon "checkmark" -Color "00FF00"
Send-Toast -Message "Disk Space Low" -Icon "warning" -Subtitle "Only 5GB remaining" -Color "FFA500"
```

### Bash

```bash theme={null}
#!/bin/bash

API_KEY="YOUR_API_KEY_HERE"
BASE_URL="http://localhost:8889"

send_toast() {
    local message="$1"
    local icon="${2:-bell}"
    local subtitle="$3"
    local duration_ms="${4:-3000}"
    local color="$5"

    local json="{\"message\":\"$message\",\"icon\":\"$icon\""

    [ -n "$subtitle" ] && json="$json,\"subtitle\":\"$subtitle\""
    [ -n "$duration_ms" ] && json="$json,\"duration_ms\":$duration_ms"
    [ -n "$color" ] && json="$json,\"color\":\"$color\""

    json="$json}"

    curl -X POST "$BASE_URL/api/toast/send" \
        -H "X-API-Key: $API_KEY" \
        -H "Content-Type: application/json" \
        -d "$json"
}

# Examples
send_toast "Tests Passed" "checkmark" "" 3000 "00FF00"
send_toast "Build Started" "settings" "Running webpack..." 5000 "0080FF"
```

## Use Cases

### CI/CD Integration

**GitHub Actions**:

```yaml theme={null}
- name: Notify Build Complete
  run: |
    curl -X POST http://YOUR_SERVER:8889/api/toast/send \
      -H "X-API-Key: ${{ secrets.TOAST_API_KEY }}" \
      -H "Content-Type: application/json" \
      -d '{"message": "Build Complete", "icon": "checkmark", "color": "00FF00"}'
```

**Jenkins Pipeline**:

```groovy theme={null}
post {
    success {
        sh '''
            curl -X POST http://localhost:8889/api/toast/send \
              -H "X-API-Key: ${TOAST_API_KEY}" \
              -H "Content-Type: application/json" \
              -d '{"message": "Deploy Success", "icon": "checkmark", "color": "00FF00"}'
        '''
    }
    failure {
        sh '''
            curl -X POST http://localhost:8889/api/toast/send \
              -H "X-API-Key: ${TOAST_API_KEY}" \
              -H "Content-Type: application/json" \
              -d '{"message": "Deploy Failed", "icon": "close", "color": "FF0000"}'
        '''
    }
}
```

### Server Monitoring

```python theme={null}
# Monitor disk space
import psutil

def check_disk_space():
    disk = psutil.disk_usage('/')
    percent_used = disk.percent

    if percent_used > 90:
        send_toast(
            "Disk Space Critical",
            icon="warning",
            subtitle=f"{percent_used}% used",
            color="FF0000",
            duration_ms=10000
        )
    elif percent_used > 75:
        send_toast(
            "Disk Space Low",
            icon="warning",
            subtitle=f"{percent_used}% used",
            color="FFA500"
        )
```

### Task Automation

```python theme={null}
# Long-running task completion
import time

def process_data():
    # Long task...
    time.sleep(3600)

    send_toast(
        "Data Processing Complete",
        icon="checkmark",
        subtitle="1000 records processed",
        color="00FF00"
    )
```

## HTTPS with Tailscale

For secure remote access, use Tailscale with HTTPS:

1. **Install Tailscale**: [https://tailscale.com/download](https://tailscale.com/download)
2. **Enable MagicDNS**: In Tailscale admin console
3. **Generate Certificates**:
   ```bash theme={null}
   tailscale cert yourhostname.tailnet.ts.net
   ```
4. **Place Certificates**: Copy `.crt` and `.key` files to `main/certs/` folder
5. **Restart App**: API server will automatically detect and use HTTPS

Your API will now be available at:

```
https://yourhostname.tailnet.ts.net:8889
```

## Troubleshooting

### Cannot Connect to API

1. **Check if server is running**:
   ```bash theme={null}
   curl http://localhost:8889/api/toast/health
   ```

2. **Check firewall**: Ensure port 8889 is not blocked

3. **Check device connection**: API requires device to be connected

### Unauthorized Errors

1. **Verify API key**: Check `mixer_config.json` for `toast_api_key`
2. **Check header format**: Use `X-API-Key` (case-sensitive)
3. **Regenerate key**: Use desktop app settings or restart server

### Rate Limit Errors

1. **Wait**: Rate limits reset after 60 seconds
2. **Reduce frequency**: Send max 30 requests per minute
3. **Batch notifications**: Combine multiple events into single notification

## Security Considerations

* **API Key Storage**: Store API keys securely (environment variables, secrets manager)
* **Local Network**: API accessible to anyone on your network by default
* **Tailscale**: Recommended for secure remote access
* **HTTPS**: Use Tailscale certificates for encrypted communication
* **Firewall**: Block port 8889 from internet if not using Tailscale

***

**Documentation Version**: 1.0
**Last Updated**: 2025-12-10
**API Port**: 8889
