# Lambda IoT Core API Documentation

## Overview

The Lambda IoT Core API provides a RESTful interface for managing IoT devices, sensors, actors, and sensor readings. The API uses JWT authentication for protected endpoints and integrates with MQTT for real-time device communication.

**Base URL**: `http://localhost:8080` (default)

## Authentication

Most endpoints require JWT authentication. Include the token in the `Authorization` header:

```
Authorization: Bearer <your-jwt-token>
```

Tokens are obtained through the `/login` endpoint and are valid for 24 hours.

---

## Public Endpoints

### Health Check

Check the service health status.

**Endpoint**: `GET /health`

**Authentication**: None required

**Response**:
```json
{
  "status": "ok"
}
```

---

### Hello

Simple greeting endpoint for testing connectivity.

**Endpoint**: `GET /hello`

**Authentication**: None required

**Response**:
```json
{
  "message": "hello from lambdaiot"
}
```

---

### Register

Create a new user account.

**Endpoint**: `POST /register`

**Authentication**: None required

**Request Body**:
```json
{
  "username": "string (required, min: 3, max: 50)",
  "password": "string (required, min: 6)",
  "email": "string (optional)"
}
```

**Response** (201 Created):
```json
{
  "id": "uuid",
  "username": "string"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid request format
- `409 Conflict`: Username already exists
- `500 Internal Server Error`: Database or server error

---

### Login

Authenticate and receive a JWT token.

**Endpoint**: `POST /login`

**Authentication**: None required

**Request Body**:
```json
{
  "username": "string",
  "password": "string"
}
```

**Response** (200 OK):
```json
{
  "token": "jwt-token-string"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid JSON
- `401 Unauthorized`: Invalid credentials
- `500 Internal Server Error`: Database or token generation error

---

### List All Devices

Retrieve all devices in the system (public read access).

**Endpoint**: `GET /devices`

**Authentication**: None required

**Response** (200 OK):
```json
[
  {
    "id": "uuid",
    "name": "string",
    "description": "string",
    "location": "string",
    "status_id": 1,
    "created_at": "2026-01-14T10:00:00Z",
    "updated_at": "2026-01-14T10:00:00Z"
  }
]
```

**Status IDs**:
- `1`: ok
- `2`: pending
- `3`: lost
- `4`: disabled

---

## Protected Endpoints

All endpoints below require JWT authentication.

### Protected Test

Test authentication and view token claims.

**Endpoint**: `GET /protected`

**Authentication**: Required

**Response** (200 OK):
```json
{
  "claims": {
    "sub": "username",
    "user_id": "uuid",
    "exp": 1705324800
  }
}
```

---

## Device Endpoints

### Create Device

Create a new device.

**Endpoint**: `POST /devices`

**Authentication**: Required

**Request Body**:
```json
{
  "name": "string (required)",
  "description": "string (required)",
  "location": "string (required)",
  "status_id": 1 (required, range: 1-4)
}
```

**Response** (201 Created):
```json
{
  "id": "uuid"
}
```

---

### Get Device

Retrieve a specific device by ID.

**Endpoint**: `GET /devices/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Device UUID

**Response** (200 OK):
```json
{
  "id": "uuid",
  "name": "string",
  "description": "string",
  "location": "string",
  "status_id": 1,
  "created_at": "2026-01-14T10:00:00Z",
  "updated_at": "2026-01-14T10:00:00Z"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid device ID
- `404 Not Found`: Device not found

---

### Update Device

Update an existing device.

**Endpoint**: `PUT /devices/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Device UUID

**Request Body** (all fields optional):
```json
{
  "name": "string",
  "description": "string",
  "location": "string",
  "status_id": 1
}
```

**Response** (200 OK):
```json
{
  "message": "device updated"
}
```

---

### Delete Device

Delete a device.

**Endpoint**: `DELETE /devices/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Device UUID

**Response** (200 OK):
```json
{
  "message": "device deleted"
}
```

---

## Sensor Endpoints

### Create Sensor

Create a new sensor for a device.

**Endpoint**: `POST /sensors`

**Authentication**: Required

**Request Body**:
```json
{
  "device_id": "uuid (required)",
  "name": "string (required)",
  "type": "string (required)",
  "data_type_id": 1 (required, min: 1)
}
```

**Response** (201 Created):
```json
{
  "id": "uuid"
}
```

---

### List All Sensors

Retrieve all sensors.

**Endpoint**: `GET /sensors`

**Authentication**: Required

**Response** (200 OK):
```json
[
  {
    "id": "uuid",
    "device_id": "uuid",
    "name": "string",
    "type": "string",
    "data_type_id": 1,
    "created_at": "2026-01-14T10:00:00Z",
    "updated_at": "2026-01-14T10:00:00Z"
  }
]
```

---

### Get Sensor

Retrieve a specific sensor by ID.

**Endpoint**: `GET /sensors/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Sensor UUID

**Response** (200 OK):
```json
{
  "id": "uuid",
  "device_id": "uuid",
  "name": "string",
  "type": "string",
  "data_type_id": 1,
  "created_at": "2026-01-14T10:00:00Z",
  "updated_at": "2026-01-14T10:00:00Z"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid sensor ID
- `404 Not Found`: Sensor not found

---

### Update Sensor

Update an existing sensor.

**Endpoint**: `PUT /sensors/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Sensor UUID

**Request Body** (all fields optional):
```json
{
  "device_id": "uuid",
  "name": "string",
  "type": "string",
  "data_type_id": 1
}
```

**Response** (200 OK):
```json
{
  "message": "sensor updated"
}
```

---

### Delete Sensor

Delete a sensor.

**Endpoint**: `DELETE /sensors/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Sensor UUID

**Response** (200 OK):
```json
{
  "message": "sensor deleted"
}
```

---

### Trigger Sensor

Request a new reading from a sensor via MQTT.

**Endpoint**: `POST /sensors/:id/trigger`

**Authentication**: Required

**Path Parameters**:
- `id`: Sensor UUID

**Request Body** (optional):
```json
{
  "action": "string (default: 'read')"
}
```

**Response** (202 Accepted):
```json
{
  "status": "published",
  "topic": "lambdaiot"
}
```

**MQTT Message Published**:
```json
{
  "type": "sensor_trigger",
  "sensor_id": "uuid",
  "action": "read",
  "requested_at": "2026-01-14T10:00:00Z"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid sensor ID
- `404 Not Found`: Sensor not found
- `500 Internal Server Error`: Failed to publish to MQTT

---

## Actor Endpoints

### Create Actor

Create a new actor for a device.

**Endpoint**: `POST /actors`

**Authentication**: Required

**Request Body**:
```json
{
  "device_id": "uuid (required)",
  "name": "string (required)",
  "type": "string (required)",
  "data_type_id": 1 (required, min: 1)
}
```

**Response** (201 Created):
```json
{
  "id": "uuid"
}
```

---

### List All Actors

Retrieve all actors.

**Endpoint**: `GET /actors`

**Authentication**: Required

**Response** (200 OK):
```json
[
  {
    "id": "uuid",
    "device_id": "uuid",
    "name": "string",
    "type": "string",
    "data_type_id": 1,
    "created_at": "2026-01-14T10:00:00Z",
    "updated_at": "2026-01-14T10:00:00Z"
  }
]
```

---

### Get Actor

Retrieve a specific actor by ID.

**Endpoint**: `GET /actors/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Actor UUID

**Response** (200 OK):
```json
{
  "id": "uuid",
  "device_id": "uuid",
  "name": "string",
  "type": "string",
  "data_type_id": 1,
  "created_at": "2026-01-14T10:00:00Z",
  "updated_at": "2026-01-14T10:00:00Z"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid actor ID
- `404 Not Found`: Actor not found

---

### Update Actor

Update an existing actor.

**Endpoint**: `PUT /actors/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Actor UUID

**Request Body** (all fields optional):
```json
{
  "device_id": "uuid",
  "name": "string",
  "type": "string",
  "data_type_id": 1
}
```

**Response** (200 OK):
```json
{
  "message": "actor updated"
}
```

---

### Delete Actor

Delete an actor.

**Endpoint**: `DELETE /actors/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Actor UUID

**Response** (200 OK):
```json
{
  "message": "actor deleted"
}
```

---

### Write to Actor

Send a command to an actor via MQTT.

**Endpoint**: `POST /actors/:id/write`

**Authentication**: Required

**Path Parameters**:
- `id`: Actor UUID

**Request Body**:
```json
{
  "action": "string (required)",
  "value": "any JSON value (optional)"
}
```

**Response** (202 Accepted):
```json
{
  "status": "published",
  "topic": "lambdaiot"
}
```

**MQTT Message Published**:
```json
{
  "type": "actor_command",
  "actor_id": "uuid",
  "action": "string",
  "value": "any",
  "requested_at": "2026-01-14T10:00:00Z"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid actor ID or missing action
- `404 Not Found`: Actor not found
- `500 Internal Server Error`: Failed to publish to MQTT

---

## Sensor Reading Endpoints

### Create Sensor Reading

Create a new sensor reading.

**Endpoint**: `POST /sensor-readings`

**Authentication**: Required

**Request Body**:
```json
{
  "sensor_id": "uuid (required)",
  "value": 123.45 (required),
  "value_at": "2026-01-14T10:00:00Z (optional, defaults to now)"
}
```

**Response** (201 Created):
```json
{
  "id": 123
}
```

---

### List Sensor Readings

Retrieve sensor readings with optional filtering and pagination.

**Endpoint**: `GET /sensor-readings`

**Authentication**: Required

**Query Parameters**:
- `sensor_id`: Filter by sensor UUID (optional)
- `limit`: Number of results (default: 100, max: 1000)
- `page`: Page number for pagination (default: 0)

**Response** (200 OK):
```json
[
  {
    "id": 123,
    "sensor_id": "uuid",
    "value": 123.45,
    "value_at": "2026-01-14T10:00:00Z"
  }
]
```

---

### Get Sensor Reading

Retrieve a specific sensor reading by ID.

**Endpoint**: `GET /sensor-readings/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Reading ID (integer)

**Response** (200 OK):
```json
{
  "id": 123,
  "sensor_id": "uuid",
  "value": 123.45,
  "value_at": "2026-01-14T10:00:00Z"
}
```

**Error Responses**:
- `400 Bad Request`: Invalid reading ID
- `404 Not Found`: Reading not found

---

### Update Sensor Reading

Update an existing sensor reading.

**Endpoint**: `PUT /sensor-readings/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Reading ID (integer)

**Request Body** (all fields optional):
```json
{
  "value": 123.45,
  "value_at": "2026-01-14T10:00:00Z"
}
```

**Response** (200 OK):
```json
{
  "message": "sensor reading updated"
}
```

---

### Delete Sensor Reading

Delete a sensor reading.

**Endpoint**: `DELETE /sensor-readings/:id`

**Authentication**: Required

**Path Parameters**:
- `id`: Reading ID (integer)

**Response** (200 OK):
```json
{
  "message": "sensor reading deleted"
}
```

---

## MQTT & System Endpoints

### MQTT Ping

Publish a ping message to the MQTT broker for testing.

**Endpoint**: `GET /mqttping`

**Authentication**: Required

**Response** (200 OK):
```json
{
  "timestamp": "2026-01-14T10:00:00Z",
  "topic": "lambdaiot"
}
```

**MQTT Message Published**:
```json
{
  "type": "ping",
  "timestamp": "2026-01-14T10:00:00Z"
}
```

---

## MQTT Integration

### Device Discovery

Devices can announce themselves by publishing to the discovery topic:

**Topic**: `{configured_mqtt_topic}/discovery`

**Message Format**:
```json
{
  "mac_address": "00:11:22:33:44:55",
  "device": {
    "id": "uuid",
    "name": "Device Name",
    "description": "Device Description",
    "location": "Device Location",
    "status_id": 1
  },
  "sensors": [
    {
      "id": "uuid",
      "name": "Temperature Sensor",
      "type": "temperature",
      "data_type_id": 1
    }
  ],
  "actors": [
    {
      "id": "uuid",
      "name": "LED Actuator",
      "type": "led",
      "data_type_id": 2
    }
  ]
}
```

**Behavior**:
- New devices are automatically created with all sensors and actors
- Existing devices are updated, and sensors/actors are synced
- Device status is set to OK (1) upon discovery (payload `device.status_id` is ignored)

---

### Device Check (State Polling)

The server periodically publishes device check requests to the main MQTT topic and
expects devices to respond on the same topic.

**Topic**: `{configured_mqtt_topic}`

**Request Message Published**:
```json
{
  "type": "device_check_request",
  "device_id": "uuid",
  "requested_at": "2026-01-14T10:00:00Z"
}
```

**Expected Device Response**:
```json
{
  "type": "device_check_response",
  "device_id": "uuid",
  "status": "ok" | "lost" | "pending"
}
```

---

### Sensor Readings via MQTT

Devices can publish sensor readings directly to the main MQTT topic. The server
stores readings only if the `sensor_id` exists in the database.

**Topic**: `{configured_mqtt_topic}`

**Message Format**:
```json
{
  "type": "sensor_reading",
  "sensor_id": "uuid",
  "value": 23.7,
  "value_at": "2026-01-14T10:00:00Z"
}
```

**Notes**:
- `type` may also be `sensor_value`.
- `value` may be a number, boolean, or numeric string (e.g., "1", "0", "23.7").
- `value_at` is optional; if omitted, the server uses the current time.

---

## Error Responses

All endpoints may return the following standard error responses:

### 400 Bad Request
```json
{
  "error": "descriptive error message"
}
```

### 401 Unauthorized
```json
{
  "error": "invalid credentials" // or "no claims"
}
```

### 404 Not Found
```json
{
  "error": "resource not found"
}
```

### 409 Conflict
```json
{
  "error": "resource already exists"
}
```

### 500 Internal Server Error
```json
{
  "error": "descriptive error message"
}
```

---

## Data Types

### Device Status IDs

| ID | Status   | Description                          |
|----|----------|--------------------------------------|
| 1  | OK       | Device is online and functioning     |
| 2  | Pending  | Device is initializing or awaiting   |
| 3  | Lost     | Device has not checked in recently   |
| 4  | Disabled | Device is administratively disabled  |

### Date/Time Format

All timestamps use RFC3339 format: `2026-01-14T10:00:00Z`

### UUIDs

UUIDs follow the standard UUID format (any version), e.g. `550e8400-e29b-41d4-a716-446655440000`.

---

## Configuration

The server uses a configuration file (typically `config.toml`) with the following structure:

```toml
[server]
address = ":8080"
port = 8080
jwt_secret = "your-secret-key"

[database]
host = "localhost"
port = 3306
user = "root"
password = "password"
name = "lambdaiot"

[mqtt]
broker = "tcp://localhost:1883"
topic = "lambdaiot"
client_id = "lambdaiot-core"
username = ""
password = ""
```

---

## Rate Limiting & Best Practices

1. **Pagination**: Use `limit` and `page` parameters for large result sets
2. **MQTT Topics**: All MQTT messages are published to the configured topic
3. **Token Expiry**: JWT tokens expire after 24 hours - refresh as needed
4. **UUID Format**: Always use valid UUID v4 format for device, sensor, and actor IDs
5. **Date Format**: Use RFC3339 format for all timestamp fields
6. **Device Discovery**: Devices can self-register via MQTT discovery messages

---

## Example Workflows

### Complete Device Setup Workflow

1. Register a user:
   ```bash
   POST /register
   {"username": "admin", "password": "secret123"}
   ```

2. Login and get token:
   ```bash
   POST /login
   {"username": "admin", "password": "secret123"}
   ```

3. Create a device:
   ```bash
   POST /devices (with JWT)
   {"name": "Room Sensor", "description": "Living room", "location": "Floor 1", "status_id": 1}
   ```

4. Create a sensor:
   ```bash
   POST /sensors (with JWT)
   {"device_id": "device-uuid", "name": "Temperature", "type": "temp", "data_type_id": 1}
   ```

5. Trigger a reading:
   ```bash
   POST /sensors/{sensor-id}/trigger (with JWT)
   {"action": "read"}
   ```

6. Create a reading:
   ```bash
   POST /sensor-readings (with JWT)
   {"sensor_id": "sensor-uuid", "value": 22.5}
   ```

### Query Readings for a Specific Sensor

```bash
GET /sensor-readings?sensor_id={uuid}&limit=50&page=0 (with JWT)
```

---

## Support & Documentation

For more information about device discovery specifications, see [DEVICE_DISCOVERY_SPEC.md](DEVICE_DISCOVERY_SPEC.md).

---

*Generated: January 14, 2026*
