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

# Fleet API

> REST API reference for fleet management resources

REST API endpoints for managing devices, recordings, events, rules, and alerts across your fleet. All endpoints require authentication via API key.

<Warning>
  The Fleet API is in preview. Endpoints described on this page may change.
</Warning>

## Base URL

All Fleet API requests use the standard Avala API base URL:

```
https://api.avala.ai/api/v1/fleet
```

Authenticate every request with your API key in the `X-Avala-Api-Key` header. See [Authentication](/docs/api-reference/authentication) for details on creating and managing keys.

***

## Devices

Register, list, and manage devices in your fleet.

### List Devices

```
GET /api/v1/fleet/devices/
```

Returns all devices in your organization.

**Query Parameters**

| Parameter  | Type    | Description                                                        |
| ---------- | ------- | ------------------------------------------------------------------ |
| `status`   | string  | Filter by device status: `online`, `offline`, `maintenance`        |
| `type`     | string  | Filter by device type (e.g., `manipulator`, `amr`, `vehicle`)      |
| `tags`     | string  | Comma-separated tag filter                                         |
| `metadata` | string  | JSON-encoded metadata filter (e.g., `{"location": "warehouse-1"}`) |
| `limit`    | integer | Results per page (default: `50`, max: `200`)                       |
| `cursor`   | string  | Pagination cursor                                                  |

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/devices/?status=online" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  from avala import Client

  client = Client(api_key="your-api-key")

  devices = client.fleet.devices.list(status="online")
  for device in devices:
      print(device.name, device.status)
  ```

  ```typescript TypeScript SDK theme={null}
  import Avala from "@avala-ai/sdk";

  const avala = new Avala({ apiKey: "your-api-key" });

  const devices = await avala.fleet.devices.list({ status: "online" });
  for (const device of devices.items) {
    console.log(device.name, device.status);
  }
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "next": "https://api.avala.ai/api/v1/fleet/devices/?cursor=eyJpZCI6MTB9",
  "previous": null,
  "results": [
    {
      "uid": "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "robot-alpha-01",
      "type": "amr",
      "status": "online",
      "tags": ["warehouse", "floor-2"],
      "last_seen_at": "2026-02-26T14:30:00Z",
      "firmware_version": "2.4.1",
      "metadata": {
        "model": "AMR-500",
        "location": "Building A"
      },
      "created_at": "2025-11-01T08:00:00Z",
      "updated_at": "2026-02-26T14:30:00Z"
    }
  ]
}
```

### Register Device

```
POST /api/v1/fleet/devices/
```

Register a new device in your fleet.

**Request Body**

| Field              | Type   | Required | Description                                       |
| ------------------ | ------ | -------- | ------------------------------------------------- |
| `name`             | string | Yes      | Human-readable device name                        |
| `type`             | string | No       | Device type (e.g., `manipulator`, `amr`, `drone`) |
| `firmware_version` | string | No       | Current firmware version                          |
| `tags`             | array  | No       | Tags for organizing devices                       |
| `metadata`         | object | No       | Arbitrary key-value metadata                      |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.avala.ai/api/v1/fleet/devices/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "robot-alpha-02",
      "tags": ["warehouse", "floor-1"],
      "metadata": {
        "model": "AMR-500",
        "location": "Building A"
      }
    }'
  ```

  ```python Python SDK theme={null}
  device = client.fleet.devices.register(
      name="robot-alpha-02",
      tags=["warehouse", "floor-1"],
      metadata={"model": "AMR-500", "location": "Building A"},
  )
  print(device.uid)
  ```

  ```typescript TypeScript SDK theme={null}
  const device = await avala.fleet.devices.register({
    name: "robot-alpha-02",
    tags: ["warehouse", "floor-1"],
    metadata: { model: "AMR-500", location: "Building A" },
  });
  console.log(device.uid);
  ```
</CodeGroup>

**Response** `201 Created`

```json theme={null}
{
  "uid": "dev_f7e8d9c0-b1a2-3456-cdef-789012345678",
  "name": "robot-alpha-02",
  "status": "offline",
  "tags": ["warehouse", "floor-1"],
  "last_seen_at": null,
  "firmware_version": null,
  "metadata": {
    "model": "AMR-500",
    "location": "Building A"
  },
  "device_token": "dtk_abc123def456...",
  "created_at": "2026-02-26T15:00:00Z",
  "updated_at": "2026-02-26T15:00:00Z"
}
```

<Warning>
  The `device_token` is returned only in the create response. Store it securely -- it cannot be retrieved again. The device uses this token to authenticate when uploading recordings.
</Warning>

### Get Device

```
GET /api/v1/fleet/devices/{uid}/
```

Returns the full details of a single device.

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/devices/dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890/" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  device = client.fleet.devices.get("dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890")
  ```

  ```typescript TypeScript SDK theme={null}
  const device = await avala.fleet.devices.get("dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890");
  ```
</CodeGroup>

### Update Device

```
PATCH /api/v1/fleet/devices/{uid}/
```

Update a device's name, tags, or metadata. Only provided fields are modified.

| Field              | Type   | Description                                       |
| ------------------ | ------ | ------------------------------------------------- |
| `name`             | string | Updated device name                               |
| `status`           | string | Device status: `online`, `offline`, `maintenance` |
| `firmware_version` | string | Current firmware version                          |
| `tags`             | array  | Replacement tags (replaces all existing tags)     |
| `metadata`         | object | Replacement metadata (merged with existing)       |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH "https://api.avala.ai/api/v1/fleet/devices/dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{"tags": ["warehouse", "floor-3"]}'
  ```

  ```python Python SDK theme={null}
  device = client.fleet.devices.update(
      device_id="dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      tags=["warehouse", "floor-3"],
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const device = await avala.fleet.devices.update({
    deviceId: "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    tags: ["warehouse", "floor-3"],
  });
  ```
</CodeGroup>

### Deregister Device

```
DELETE /api/v1/fleet/devices/{uid}/
```

Remove a device from your fleet. Recordings associated with the device are not deleted.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE "https://api.avala.ai/api/v1/fleet/devices/dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890/" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  client.fleet.devices.deregister(device_id="dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890")
  ```

  ```typescript TypeScript SDK theme={null}
  await avala.fleet.devices.deregister({ deviceId: "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890" });
  ```
</CodeGroup>

**Response** `204 No Content`

### Device Fields

| Field              | Type              | Description                                       |
| ------------------ | ----------------- | ------------------------------------------------- |
| `uid`              | string            | Unique device identifier                          |
| `name`             | string            | Human-readable name                               |
| `type`             | string            | Device type (e.g., `manipulator`, `amr`, `drone`) |
| `status`           | string            | `online`, `offline`, or `maintenance`             |
| `tags`             | array             | Organization tags                                 |
| `last_seen_at`     | string (ISO 8601) | Last heartbeat timestamp                          |
| `firmware_version` | string            | Reported firmware version                         |
| `metadata`         | object            | Arbitrary key-value metadata                      |
| `created_at`       | string (ISO 8601) | Registration timestamp                            |
| `updated_at`       | string (ISO 8601) | Last update timestamp                             |

***

## Recordings

List, filter, and manage recordings uploaded by fleet devices.

### List Recordings

```
GET /api/v1/fleet/recordings/
```

Returns recordings across your fleet, ordered by creation date descending.

**Query Parameters**

| Parameter   | Type              | Description                                                               |
| ----------- | ----------------- | ------------------------------------------------------------------------- |
| `device_id` | string            | Filter by device UID                                                      |
| `status`    | string            | Filter by status: `uploading`, `processing`, `ready`, `error`, `archived` |
| `since`     | string (ISO 8601) | Return recordings created after this timestamp                            |
| `until`     | string (ISO 8601) | Return recordings created before this timestamp                           |
| `tags`      | string            | Comma-separated tag filter                                                |
| `limit`     | integer           | Results per page (default: `50`, max: `200`)                              |
| `cursor`    | string            | Pagination cursor                                                         |

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/recordings/?device_id=dev_a1b2c3d4&status=ready&since=2026-02-01T00:00:00Z" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  recordings = client.fleet.recordings.list(
      device_id="dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      status="ready",
      since="2026-02-01T00:00:00Z",
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const recordings = await avala.fleet.recordings.list({
    deviceId: "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    status: "ready",
    since: "2026-02-01T00:00:00Z",
  });
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "next": null,
  "previous": null,
  "results": [
    {
      "uid": "rec_11223344-5566-7788-99aa-bbccddeeff00",
      "device_id": "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "device_name": "robot-alpha-01",
      "status": "ready",
      "duration_seconds": 342.5,
      "size_bytes": 1073741824,
      "topic_count": 12,
      "tags": ["mission-47", "outdoor"],
      "started_at": "2026-02-26T10:00:00Z",
      "ended_at": "2026-02-26T10:05:42Z",
      "created_at": "2026-02-26T10:06:00Z"
    }
  ]
}
```

### Get Recording

```
GET /api/v1/fleet/recordings/{uid}/
```

Returns full recording details including topic list and processing metadata.

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/recordings/rec_11223344-5566-7788-99aa-bbccddeeff00/" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  recording = client.fleet.recordings.get("rec_11223344-5566-7788-99aa-bbccddeeff00")
  ```

  ```typescript TypeScript SDK theme={null}
  const recording = await avala.fleet.recordings.get("rec_11223344-5566-7788-99aa-bbccddeeff00");
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "uid": "rec_11223344-5566-7788-99aa-bbccddeeff00",
  "device_id": "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "device_name": "robot-alpha-01",
  "status": "ready",
  "duration_seconds": 342.5,
  "size_bytes": 1073741824,
  "topic_count": 12,
  "tags": ["mission-47", "outdoor"],
  "topics": [
    {
      "name": "/camera/front/image",
      "schema": "sensor_msgs/Image",
      "message_count": 3425,
      "frequency_hz": 10.0
    },
    {
      "name": "/lidar/points",
      "schema": "sensor_msgs/PointCloud2",
      "message_count": 3425,
      "frequency_hz": 10.0
    }
  ],
  "started_at": "2026-02-26T10:00:00Z",
  "ended_at": "2026-02-26T10:05:42Z",
  "created_at": "2026-02-26T10:06:00Z"
}
```

### Update Recording

```
PATCH /api/v1/fleet/recordings/{uid}/
```

Update a recording's tags or status.

| Field    | Type   | Description                                |
| -------- | ------ | ------------------------------------------ |
| `tags`   | array  | Replacement tags                           |
| `status` | string | Set to `archived` to archive the recording |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH "https://api.avala.ai/api/v1/fleet/recordings/rec_11223344-5566-7788-99aa-bbccddeeff00/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{"tags": ["mission-47", "outdoor", "reviewed"]}'
  ```

  ```python Python SDK theme={null}
  recording = client.fleet.recordings.update(
      recording_id="rec_11223344-5566-7788-99aa-bbccddeeff00",
      tags=["mission-47", "outdoor", "reviewed"],
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const recording = await avala.fleet.recordings.update({
    recordingId: "rec_11223344-5566-7788-99aa-bbccddeeff00",
    tags: ["mission-47", "outdoor", "reviewed"],
  });
  ```
</CodeGroup>

### Delete Recording

```
DELETE /api/v1/fleet/recordings/{uid}/
```

Permanently delete a recording and all associated data.

<Warning>
  This action is irreversible. All recording data, events, and associated files are permanently removed.
</Warning>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE "https://api.avala.ai/api/v1/fleet/recordings/rec_11223344-5566-7788-99aa-bbccddeeff00/" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  client.fleet.recordings.delete("rec_11223344-5566-7788-99aa-bbccddeeff00")
  ```

  ```typescript TypeScript SDK theme={null}
  await avala.fleet.recordings.delete("rec_11223344-5566-7788-99aa-bbccddeeff00");
  ```
</CodeGroup>

**Response** `204 No Content`

### Recording Fields

| Field              | Type              | Description                                                |
| ------------------ | ----------------- | ---------------------------------------------------------- |
| `uid`              | string            | Unique recording identifier                                |
| `device_id`        | string            | UID of the device that created the recording               |
| `device_name`      | string            | Human-readable device name                                 |
| `status`           | string            | `uploading`, `processing`, `ready`, `error`, or `archived` |
| `duration_seconds` | number            | Recording duration in seconds                              |
| `size_bytes`       | integer           | Total file size in bytes                                   |
| `topic_count`      | integer           | Number of topics in the recording                          |
| `tags`             | array             | Organization tags                                          |
| `topics`           | array             | Topic details (only in detail endpoint)                    |
| `started_at`       | string (ISO 8601) | Recording start timestamp                                  |
| `ended_at`         | string (ISO 8601) | Recording end timestamp                                    |
| `created_at`       | string (ISO 8601) | Upload timestamp                                           |

***

## Events

Create and query timeline events associated with recordings.

### List Events

```
GET /api/v1/fleet/events/
```

Returns events across your fleet, ordered by timestamp descending.

**Query Parameters**

| Parameter         | Type              | Description                                                                           |
| ----------------- | ----------------- | ------------------------------------------------------------------------------------- |
| `recording_id`    | string            | Filter by recording UID                                                               |
| `device_id`       | string            | Filter by device UID                                                                  |
| `type`            | string            | Filter by event type: `error`, `warning`, `info`, `state_change`, `anomaly`, `custom` |
| `severity`        | string            | Filter by severity: `info`, `warning`, `error`, `critical`                            |
| `since`           | string (ISO 8601) | Return events after this timestamp                                                    |
| `until`           | string (ISO 8601) | Return events before this timestamp                                                   |
| `order_by`        | string            | Sort order: `timestamp` (ascending) or `-timestamp` (descending, default)             |
| `metadata_filter` | string            | JSON-encoded metadata query (e.g., `{"motor_id": "joint_3"}`)                         |
| `tags`            | string            | Comma-separated tag filter                                                            |
| `limit`           | integer           | Results per page (default: `50`, max: `200`)                                          |
| `cursor`          | string            | Pagination cursor                                                                     |

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/events/?recording_id=rec_11223344&severity=error" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  events = client.fleet.events.list(
      recording_id="rec_11223344-5566-7788-99aa-bbccddeeff00",
      severity="error",
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const events = await avala.fleet.events.list({
    recordingId: "rec_11223344-5566-7788-99aa-bbccddeeff00",
    severity: "error",
  });
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "next": null,
  "previous": null,
  "results": [
    {
      "uid": "evt_aabbccdd-eeff-0011-2233-445566778899",
      "recording_id": "rec_11223344-5566-7788-99aa-bbccddeeff00",
      "device_id": "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "type": "anomaly",
      "label": "LiDAR topic /lidar/points dropped 15 messages in 2s window",
      "severity": "error",
      "timestamp": "2026-02-26T10:03:22Z",
      "metadata": {
        "topic": "/lidar/points",
        "dropped_count": 15,
        "window_seconds": 2
      },
      "created_at": "2026-02-26T10:03:22Z"
    }
  ]
}
```

### Create Event

```
POST /api/v1/fleet/events/
```

Create a new event associated with a recording or device.

**Request Body**

| Field          | Type              | Required | Description                                                                          |
| -------------- | ----------------- | -------- | ------------------------------------------------------------------------------------ |
| `recording_id` | string            | Yes      | Recording to associate the event with                                                |
| `type`         | string            | Yes      | `error`, `warning`, `info`, `state_change`, `anomaly`, or `custom`                   |
| `label`        | string            | Yes      | Human-readable event label                                                           |
| `timestamp`    | string (ISO 8601) | Yes      | When the event occurred                                                              |
| `description`  | string            | No       | Detailed description of the event                                                    |
| `duration_ms`  | number            | No       | Duration of the event in milliseconds (for span-like events)                         |
| `tags`         | array             | No       | Tags for categorizing the event                                                      |
| `metadata`     | object            | No       | Arbitrary event metadata                                                             |
| `severity`     | string            | No       | Override severity: `info`, `warning`, `error`, `critical`. Defaults based on `type`. |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.avala.ai/api/v1/fleet/events/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "recording_id": "rec_11223344-5566-7788-99aa-bbccddeeff00",
      "type": "anomaly",
      "label": "CPU usage exceeded 90% threshold",
      "timestamp": "2026-02-26T10:02:15Z",
      "metadata": {
        "cpu_percent": 93.2,
        "threshold": 90
      }
    }'
  ```

  ```python Python SDK theme={null}
  event = client.fleet.events.create(
      recording_id="rec_11223344-5566-7788-99aa-bbccddeeff00",
      type="anomaly",
      label="CPU usage exceeded 90% threshold",
      timestamp="2026-02-26T10:02:15Z",
      metadata={"cpu_percent": 93.2, "threshold": 90},
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const event = await avala.fleet.events.create({
    recordingId: "rec_11223344-5566-7788-99aa-bbccddeeff00",
    type: "anomaly",
    label: "CPU usage exceeded 90% threshold",
    timestamp: "2026-02-26T10:02:15Z",
    metadata: { cpu_percent: 93.2, threshold: 90 },
  });
  ```
</CodeGroup>

**Response** `201 Created`

### Batch Create Events

```
POST /api/v1/fleet/events/batch/
```

Create multiple events in a single request. Accepts up to 1,000 events. Events are created atomically — if any event fails validation, none are created.

**Request Body**

| Field          | Type   | Required | Description                        |
| -------------- | ------ | -------- | ---------------------------------- |
| `recording_id` | string | Yes      | Recording to attach events to      |
| `events`       | array  | Yes      | Array of event objects (max 1,000) |

Each event object accepts the same fields as `POST /api/v1/fleet/events/` (excluding `recording_id`, which is set at the top level).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.avala.ai/api/v1/fleet/events/batch/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "recording_id": "rec_11223344-5566-7788-99aa-bbccddeeff00",
      "events": [
        {"timestamp": "2026-02-26T10:02:15Z", "type": "error", "label": "Motor overtemp"},
        {"timestamp": "2026-02-26T10:02:20Z", "type": "state_change", "label": "Emergency stop"}
      ]
    }'
  ```

  ```python Python SDK theme={null}
  events = client.fleet.events.create_batch(
      recording_id="rec_11223344-5566-7788-99aa-bbccddeeff00",
      events=[
          {"timestamp": "2026-02-26T10:02:15Z", "type": "error", "label": "Motor overtemp"},
          {"timestamp": "2026-02-26T10:02:20Z", "type": "state_change", "label": "Emergency stop"},
      ],
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const result = await avala.fleet.events.createBatch({
    recordingId: "rec_11223344-5566-7788-99aa-bbccddeeff00",
    events: [
      { timestamp: "2026-02-26T10:02:15Z", type: "error", label: "Motor overtemp" },
      { timestamp: "2026-02-26T10:02:20Z", type: "state_change", label: "Emergency stop" },
    ],
  });
  ```
</CodeGroup>

**Response** `201 Created` — Returns the array of created event objects.

### Get Event

```
GET /api/v1/fleet/events/{uid}/
```

### Delete Event

```
DELETE /api/v1/fleet/events/{uid}/
```

**Response** `204 No Content`

### Event Fields

| Field          | Type              | Description                                                        |
| -------------- | ----------------- | ------------------------------------------------------------------ |
| `uid`          | string            | Unique event identifier                                            |
| `recording_id` | string            | Associated recording UID                                           |
| `device_id`    | string            | Device that generated the event (derived from recording)           |
| `type`         | string            | `error`, `warning`, `info`, `state_change`, `anomaly`, or `custom` |
| `label`        | string            | Human-readable event label                                         |
| `description`  | string            | Detailed event description                                         |
| `timestamp`    | string (ISO 8601) | When the event occurred                                            |
| `duration_ms`  | number            | Event duration in milliseconds (nullable)                          |
| `tags`         | array             | Event tags                                                         |
| `metadata`     | object            | Arbitrary metadata                                                 |
| `severity`     | string            | `info`, `warning`, `error`, or `critical`                          |
| `created_at`   | string (ISO 8601) | Server-side creation timestamp                                     |

***

## Rules

Recording rules define conditions that automatically trigger events, flag recordings, or start processing pipelines.

### List Rules

```
GET /api/v1/fleet/rules/
```

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/rules/" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  rules = client.fleet.rules.list()

  # Filter by enabled status or condition type
  rules = client.fleet.rules.list(enabled=True)
  rules = client.fleet.rules.list(condition_type="threshold")
  ```

  ```typescript TypeScript SDK theme={null}
  let rules = await avala.fleet.rules.list();

  // Filter by enabled status or condition type
  rules = await avala.fleet.rules.list({ enabled: true });
  rules = await avala.fleet.rules.list({ conditionType: "threshold" });
  ```
</CodeGroup>

**Query parameters**

| Parameter        | Type      | Description                                                                             |
| ---------------- | --------- | --------------------------------------------------------------------------------------- |
| `enabled`        | `boolean` | Filter by enabled/disabled status.                                                      |
| `condition_type` | `string`  | Filter by condition type (`threshold`, `pattern`, `frequency`, `absence`, `composite`). |

**Response**

```json theme={null}
{
  "next": null,
  "previous": null,
  "results": [
    {
      "uid": "rul_00112233-4455-6677-8899-aabbccddeeff",
      "name": "Flag high CPU recordings",
      "description": "Flag any recording where CPU exceeds 90% for more than 10 seconds",
      "enabled": true,
      "condition": {
        "type": "threshold",
        "topic": "/diagnostics/cpu",
        "field": "data.aggregate_percent",
        "operator": "gt",
        "value": 90,
        "window": "10s"
      },
      "actions": [
        {
          "type": "tag",
          "value": "high-cpu"
        },
        {
          "type": "create_event",
          "event_type": "warning",
          "label": "CPU exceeded 90% for >10s"
        }
      ],
      "scope": null,
      "hit_count": 42,
      "last_hit_at": "2026-02-25T18:45:00Z",
      "created_at": "2026-01-15T09:00:00Z",
      "updated_at": "2026-02-20T11:30:00Z"
    }
  ]
}
```

### Create Rule

```
POST /api/v1/fleet/rules/
```

**Request Body**

| Field         | Type    | Required | Description                                                                                |
| ------------- | ------- | -------- | ------------------------------------------------------------------------------------------ |
| `name`        | string  | Yes      | Human-readable rule name                                                                   |
| `description` | string  | No       | Description of the rule's purpose                                                          |
| `enabled`     | boolean | No       | Whether the rule is active (default: `true`)                                               |
| `condition`   | object  | Yes      | Trigger condition (see below)                                                              |
| `actions`     | array   | Yes      | Actions to execute when the condition is met                                               |
| `scope`       | object  | No       | Limit rule to specific devices or groups. Contains `device_ids` and/or `group_ids` arrays. |

**Condition Types**

| Type        | Description                                                 | Required Fields                                          |
| ----------- | ----------------------------------------------------------- | -------------------------------------------------------- |
| `threshold` | Fires when a topic field exceeds a value                    | `topic`, `field`, `operator`, `value`, optional `window` |
| `pattern`   | Fires when a topic field matches a regex pattern            | `topic`, `field`, `regex`                                |
| `frequency` | Fires when event count crosses a threshold in a time window | `topic`, `count_operator`, `count`, `window`             |
| `absence`   | Fires when expected data is missing for a duration          | `topic`, `timeout`                                       |
| `composite` | Logical combination of other conditions                     | `operator` (`and` or `or`), `conditions`                 |

**Action Types**

| Type              | Description                           | Required Fields                            |
| ----------------- | ------------------------------------- | ------------------------------------------ |
| `tag`             | Add a tag to the recording            | `value`                                    |
| `create_event`    | Create a timeline event               | `event_type`, `label`, optional `severity` |
| `flag_for_review` | Flag the recording for manual review  | --                                         |
| `notify`          | Send notification to an alert channel | `channel_id`                               |
| `auto_label`      | Trigger an auto-labeling pipeline     | `pipeline_id`                              |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.avala.ai/api/v1/fleet/rules/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "LiDAR dropout detection",
      "description": "Detect when LiDAR data is missing for more than 2 seconds",
      "condition": {
        "type": "absence",
        "topic": "/lidar/points",
        "timeout": "2s"
      },
      "actions": [
        {"type": "create_event", "event_type": "error", "label": "LiDAR data missing for >2s"},
        {"type": "tag", "value": "lidar-dropout"},
        {"type": "notify", "channel_id": "ch_aabb1122"}
      ]
    }'
  ```

  ```python Python SDK theme={null}
  rule = client.fleet.rules.create(
      name="LiDAR dropout detection",
      description="Detect when LiDAR data is missing for more than 2 seconds",
      condition={
          "type": "absence",
          "topic": "/lidar/points",
          "timeout": "2s",
      },
      actions=[
          {"type": "create_event", "event_type": "error", "label": "LiDAR data missing for >2s"},
          {"type": "tag", "value": "lidar-dropout"},
          {"type": "notify", "channel_id": "ch_aabb1122"},
      ],
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const rule = await avala.fleet.rules.create({
    name: "LiDAR dropout detection",
    description: "Detect when LiDAR data is missing for more than 2 seconds",
    condition: {
      type: "absence",
      topic: "/lidar/points",
      timeout: "2s",
    },
    actions: [
      { type: "create_event", eventType: "error", label: "LiDAR data missing for >2s" },
      { type: "tag", value: "lidar-dropout" },
      { type: "notify", channelId: "ch_aabb1122" },
    ],
  });
  ```
</CodeGroup>

**Response** `201 Created`

### Get Rule

```
GET /api/v1/fleet/rules/{uid}/
```

### Update Rule

```
PATCH /api/v1/fleet/rules/{uid}/
```

Update a rule's name, description, enabled state, condition, or actions. Only provided fields are modified.

| Field         | Type    | Description                                             |
| ------------- | ------- | ------------------------------------------------------- |
| `name`        | string  | Updated rule name                                       |
| `description` | string  | Updated description                                     |
| `enabled`     | boolean | Set to `false` to disable the rule, `true` to re-enable |
| `condition`   | object  | Updated trigger condition                               |
| `actions`     | array   | Updated list of actions                                 |

### Delete Rule

```
DELETE /api/v1/fleet/rules/{uid}/
```

**Response** `204 No Content`

### Rule Fields

| Field         | Type              | Description                                                    |
| ------------- | ----------------- | -------------------------------------------------------------- |
| `uid`         | string            | Unique rule identifier                                         |
| `name`        | string            | Human-readable name                                            |
| `description` | string            | Rule description                                               |
| `enabled`     | boolean           | Whether the rule is active                                     |
| `condition`   | object            | Trigger condition                                              |
| `actions`     | array             | Actions to execute                                             |
| `scope`       | object            | Restricts rule to specific devices, groups, or tags (nullable) |
| `hit_count`   | integer           | Total number of times the rule has triggered                   |
| `last_hit_at` | string (ISO 8601) | When the rule last triggered (nullable)                        |
| `created_at`  | string (ISO 8601) | Creation timestamp                                             |
| `updated_at`  | string (ISO 8601) | Last update timestamp                                          |

***

## Alerts

View and manage alerts generated by recording rules and diagnostics thresholds.

### List Alerts

```
GET /api/v1/fleet/alerts/
```

Returns alerts ordered by creation date descending.

**Query Parameters**

| Parameter      | Type              | Description                                                |
| -------------- | ----------------- | ---------------------------------------------------------- |
| `device_id`    | string            | Filter by device UID                                       |
| `recording_id` | string            | Filter by recording UID                                    |
| `rule_id`      | string            | Filter by rule UID                                         |
| `channel_id`   | string            | Filter by notification channel UID                         |
| `status`       | string            | Filter by status: `open`, `acknowledged`, `resolved`       |
| `severity`     | string            | Filter by severity: `info`, `warning`, `error`, `critical` |
| `since`        | string (ISO 8601) | Return alerts created after this timestamp                 |
| `until`        | string (ISO 8601) | Return alerts created before this timestamp                |
| `limit`        | integer           | Results per page (default: `50`, max: `200`)               |
| `cursor`       | string            | Pagination cursor                                          |

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/alerts/?status=open&severity=error" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  alerts = client.fleet.alerts.list(status="open", severity="error")
  ```

  ```typescript TypeScript SDK theme={null}
  const alerts = await avala.fleet.alerts.list({ status: "open", severity: "error" });
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "next": null,
  "previous": null,
  "results": [
    {
      "uid": "alt_99887766-5544-3322-1100-ffeeddccbbaa",
      "rule_id": "rul_00112233-4455-6677-8899-aabbccddeeff",
      "rule_name": "LiDAR dropout detection",
      "device_id": "dev_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "device_name": "robot-alpha-01",
      "recording_id": "rec_11223344-5566-7788-99aa-bbccddeeff00",
      "severity": "error",
      "status": "open",
      "message": "LiDAR frequency dropped below 8 Hz",
      "triggered_at": "2026-02-26T10:03:22Z",
      "acknowledged_at": null,
      "resolved_at": null,
      "created_at": "2026-02-26T10:03:22Z"
    }
  ]
}
```

### Get Alert

```
GET /api/v1/fleet/alerts/{uid}/
```

### Acknowledge Alert

```
POST /api/v1/fleet/alerts/{uid}/acknowledge/
```

Mark an alert as acknowledged. This indicates that someone is aware of the issue and is investigating.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.avala.ai/api/v1/fleet/alerts/alt_99887766-5544-3322-1100-ffeeddccbbaa/acknowledge/" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  client.fleet.alerts.acknowledge(
      alert_id="alt_99887766-5544-3322-1100-ffeeddccbbaa",
      note="Investigating the issue"
  )
  ```

  ```typescript TypeScript SDK theme={null}
  await avala.fleet.alerts.acknowledge({
    alertId: "alt_99887766-5544-3322-1100-ffeeddccbbaa",
    note: "Investigating the issue",
  });
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "uid": "alt_99887766-5544-3322-1100-ffeeddccbbaa",
  "status": "acknowledged",
  "acknowledged_at": "2026-02-26T10:15:00Z",
  "acknowledged_by": "johndoe"
}
```

### Resolve Alert

```
POST /api/v1/fleet/alerts/{uid}/resolve/
```

Mark an alert as resolved. Optionally include a resolution note.

**Request Body**

| Field  | Type   | Required | Description                              |
| ------ | ------ | -------- | ---------------------------------------- |
| `note` | string | No       | Resolution note describing what was done |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.avala.ai/api/v1/fleet/alerts/alt_99887766-5544-3322-1100-ffeeddccbbaa/resolve/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{"note": "LiDAR sensor recalibrated and firmware updated to v2.4.2"}'
  ```

  ```python Python SDK theme={null}
  client.fleet.alerts.resolve(
      alert_id="alt_99887766-5544-3322-1100-ffeeddccbbaa",
      note="LiDAR sensor recalibrated and firmware updated to v2.4.2",
  )
  ```

  ```typescript TypeScript SDK theme={null}
  await avala.fleet.alerts.resolve({
    alertId: "alt_99887766-5544-3322-1100-ffeeddccbbaa",
    note: "LiDAR sensor recalibrated and firmware updated to v2.4.2",
  });
  ```
</CodeGroup>

### Alert Fields

| Field             | Type              | Description                                                       |
| ----------------- | ----------------- | ----------------------------------------------------------------- |
| `uid`             | string            | Unique alert identifier                                           |
| `rule_id`         | string            | Rule that triggered the alert                                     |
| `rule_name`       | string            | Human-readable rule name                                          |
| `device_id`       | string            | Device associated with the alert                                  |
| `device_name`     | string            | Human-readable device name                                        |
| `recording_id`    | string            | Recording associated with the alert (nullable)                    |
| `severity`        | string            | `info`, `warning`, `error`, or `critical`                         |
| `status`          | string            | `open`, `acknowledged`, or `resolved`                             |
| `message`         | string            | Alert description                                                 |
| `triggered_at`    | string (ISO 8601) | When the alert condition was met                                  |
| `acknowledged_at` | string (ISO 8601) | When the alert was acknowledged (nullable)                        |
| `acknowledged_by` | string            | User who acknowledged the alert (nullable)                        |
| `resolved_at`     | string (ISO 8601) | When the alert was resolved (nullable)                            |
| `duration`        | string            | Computed time between `triggered_at` and `resolved_at` (nullable) |
| `created_at`      | string (ISO 8601) | Server-side creation timestamp                                    |

***

## Alert Channels

Configure notification destinations for alerts.

### List Channels

```
GET /api/v1/fleet/alerts/channels/
```

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.avala.ai/api/v1/fleet/alerts/channels/" \
    -H "X-Avala-Api-Key: avk_your_api_key"
  ```

  ```python Python SDK theme={null}
  channels = client.fleet.alerts.channels.list()
  ```

  ```typescript TypeScript SDK theme={null}
  const channels = await avala.fleet.alerts.channels.list();
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "next": null,
  "previous": null,
  "results": [
    {
      "uid": "ch_aabb1122-3344-5566-7788-99aabbccddee",
      "name": "Engineering Slack",
      "type": "slack",
      "config": {
        "webhook_url": "https://hooks.slack.com/services/..."
      },
      "created_at": "2026-01-10T08:00:00Z"
    },
    {
      "uid": "ch_ffeeddcc-bbaa-9988-7766-554433221100",
      "name": "Ops Team Email",
      "type": "email",
      "config": {
        "recipients": ["ops@example.com"]
      },
      "created_at": "2026-01-10T08:30:00Z"
    }
  ]
}
```

### Create Channel

```
POST /api/v1/fleet/alerts/channels/
```

**Request Body**

| Field    | Type   | Required | Description                                  |
| -------- | ------ | -------- | -------------------------------------------- |
| `name`   | string | Yes      | Channel display name                         |
| `type`   | string | Yes      | Channel type: `slack`, `email`, or `webhook` |
| `config` | object | Yes      | Channel-specific configuration (see below)   |

**Channel Configuration**

| Type      | Config Fields                                                                                                                                                            |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `slack`   | `webhook_url` (required) -- Slack incoming webhook URL; `channel` -- Optional channel override; `username` -- Optional display name; `icon_emoji` -- Optional emoji icon |
| `email`   | `recipients` (required) -- Array of email addresses; `subject_prefix` -- Optional email subject prefix                                                                   |
| `webhook` | `url` (required) -- HTTP endpoint URL; `signing_secret` -- Optional HMAC signing secret; `headers` -- Optional custom headers                                            |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.avala.ai/api/v1/fleet/alerts/channels/" \
    -H "X-Avala-Api-Key: avk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Engineering Slack",
      "type": "slack",
      "config": {
        "webhook_url": "https://hooks.slack.com/services/T00/B00/xxx"
      }
    }'
  ```

  ```python Python SDK theme={null}
  channel = client.fleet.alerts.channels.create(
      name="Engineering Slack",
      type="slack",
      config={"webhook_url": "https://hooks.slack.com/services/T00/B00/xxx"},
  )
  ```

  ```typescript TypeScript SDK theme={null}
  const channel = await avala.fleet.alerts.channels.create({
    name: "Engineering Slack",
    type: "slack",
    config: { webhook_url: "https://hooks.slack.com/services/T00/B00/xxx" },
  });
  ```
</CodeGroup>

**Response** `201 Created`

### Delete Channel

```
DELETE /api/v1/fleet/alerts/channels/{uid}/
```

<Warning>
  Deleting a channel that is referenced by active rules does not delete the rules. The rules continue to function, but the `notify` action is skipped for the deleted channel.
</Warning>

**Response** `204 No Content`

### Channel Fields

| Field        | Type              | Description                    |
| ------------ | ----------------- | ------------------------------ |
| `uid`        | string            | Unique channel identifier      |
| `name`       | string            | Display name                   |
| `type`       | string            | `slack`, `email`, or `webhook` |
| `config`     | object            | Channel-specific configuration |
| `created_at` | string (ISO 8601) | Creation timestamp             |

***

## Common Patterns

### Pagination

All list endpoints use cursor-based pagination. Follow the `next` URL until it returns `null` to retrieve all results.

```json theme={null}
{
  "next": "https://api.avala.ai/api/v1/fleet/devices/?cursor=eyJpZCI6MTB9",
  "previous": null,
  "results": [...]
}
```

Use the `limit` parameter to control page size. The maximum is `200` results per page.

### Error Responses

The Fleet API uses standard Avala error responses. See [Error Codes](/docs/api-reference/errors) for the full reference.

| Status | Description                                                       |
| ------ | ----------------------------------------------------------------- |
| `400`  | Bad Request -- invalid or missing fields                          |
| `401`  | Unauthorized -- missing or invalid API key                        |
| `403`  | Forbidden -- insufficient permissions                             |
| `404`  | Not Found -- resource does not exist                              |
| `409`  | Conflict -- resource already exists (e.g., duplicate device name) |
| `429`  | Too Many Requests -- rate limit exceeded                          |

### Rate Limits

Fleet API endpoints share the standard Avala rate limits. See [Rate Limits](/docs/api-reference/rate-limits) for details.

## Additional SDK Resources

The following fleet features are available through the Python and TypeScript SDKs. REST endpoint documentation will be added as these features stabilize.

| Resource                | Description                                                       | Guide                                                                   |
| ----------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Device Groups           | Organize devices into logical groups for scoped rules and metrics | [Fleet Dashboard](/docs/visualization/fleet/fleet-dashboard)                 |
| Fleet Metrics           | Aggregate fleet statistics and time-series telemetry              | [Fleet Dashboard](/docs/visualization/fleet/fleet-dashboard)                 |
| Escalation Policies     | Define multi-stage alert escalation workflows                     | [Alerts & Notifications](/docs/visualization/fleet/alerts-and-notifications) |
| Alert Muting & Snoozing | Suppress alerts during maintenance windows                        | [Alerts & Notifications](/docs/visualization/fleet/alerts-and-notifications) |

## Next Steps

<CardGroup cols={3}>
  <Card title="" icon="satellite-dish" href="/docs/visualization/fleet/fleet-dashboard">
    <p style={{fontWeight: 600, fontSize: '18px', marginBottom: '4px', marginTop: '8px', color: 'inherit'}}>Fleet Dashboard</p>
    <p style={{fontSize: '14px', marginTop: '0px', opacity: 0.6}}>Monitor your fleet visually with the Mission Control dashboard.</p>
  </Card>

  <Card title="" icon="python" href="/docs/sdks/python">
    <p style={{fontWeight: 600, fontSize: '18px', marginBottom: '4px', marginTop: '8px', color: 'inherit'}}>Python SDK</p>
    <p style={{fontSize: '14px', marginTop: '0px', opacity: 0.6}}>Use the Python SDK for programmatic fleet management.</p>
  </Card>

  <Card title="" icon="js" href="/docs/sdks/typescript">
    <p style={{fontWeight: 600, fontSize: '18px', marginBottom: '4px', marginTop: '8px', color: 'inherit'}}>TypeScript SDK</p>
    <p style={{fontSize: '14px', marginTop: '0px', opacity: 0.6}}>Use the TypeScript SDK for Node.js and browser integrations.</p>
  </Card>
</CardGroup>
