AetherLens provides a RESTful API for managing devices, metrics, and cost calculations. The API is built with FastAPI and includes comprehensive documentation via Swagger UI.
http://localhost:8080
All API endpoints (except /health and /metrics) require authentication using JWT Bearer tokens.
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "password"
}Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"token_type": "bearer",
"expires_in": 3600
}Include the access token in the Authorization header:
curl http://localhost:8080/api/v1/devices \
-H "Authorization: Bearer <access_token>"API requests are rate limited to:
- 60 requests per minute per IP address
- 1000 requests per hour per IP address
Rate limit headers are included in all responses:
X-RateLimit-Limit-Minute: Maximum requests per minuteX-RateLimit-Remaining-Minute: Remaining requests in current minuteX-RateLimit-Limit-Hour: Maximum requests per hourX-RateLimit-Remaining-Hour: Remaining requests in current hour
GET /healthReturns status of all dependencies (database, TimescaleDB).
Response:
{
"status": "healthy",
"timestamp": "2025-10-24T20:00:00.000Z",
"version": "1.0.0",
"checks": {
"database": {
"status": "healthy",
"latency_ms": 2.5,
"message": "Database responding"
},
"timescaledb": {
"status": "healthy",
"version": "2.22.1",
"message": "TimescaleDB active"
}
}
}- Readiness:
GET /health/ready- Returns 200 when ready to accept traffic - Liveness:
GET /health/live- Returns 200 if process is alive
GET /api/v1/devices?page=1&page_size=50&type=smart_plug
Authorization: Bearer <token>Query Parameters:
page(int, default: 1): Page numberpage_size(int, default: 50, max: 100): Items per pagetype(string, optional): Filter by device type
Response:
{
"devices": [
{
"device_id": "shelly-office-01",
"name": "Office Desk Plug",
"type": "smart_plug",
"manufacturer": "Shelly",
"model": "Plug S",
"location": {"room": "office", "floor": 2},
"capabilities": ["power_monitoring", "on_off_control"],
"configuration": {"ip_address": "192.168.1.100"},
"status": {"online": true},
"created_at": "2025-10-24T10:00:00Z",
"updated_at": "2025-10-24T15:30:00Z"
}
],
"total": 3,
"page": 1,
"page_size": 50,
"pages": 1
}GET /api/v1/devices/{device_id}
Authorization: Bearer <token>POST /api/v1/devices
Authorization: Bearer <token>
Content-Type: application/json
{
"device_id": "new-device-01",
"name": "New Smart Plug",
"type": "smart_plug",
"manufacturer": "Shelly",
"model": "Plug S",
"location": {"room": "bedroom", "floor": 2},
"capabilities": ["power_monitoring"],
"configuration": {"ip_address": "192.168.1.105"}
}PUT /api/v1/devices/{device_id}
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "Updated Device Name",
"location": {"room": "living_room", "floor": 1}
}DELETE /api/v1/devices/{device_id}
Authorization: Bearer <token>Note: Deleting a device will also delete all associated metrics.
GET /metricsExposes Prometheus-formatted metrics:
aetherlens_api_requests_total- Total API requests by method, endpoint, statusaetherlens_api_request_duration_seconds- Request duration histogramaetherlens_api_requests_in_progress- Current in-progress requestsaetherlens_database_pool_size- Database connection pool sizeaetherlens_database_pool_available- Available database connections
Visit these URLs for interactive API documentation:
- Swagger UI: http://localhost:8080/docs
- ReDoc: http://localhost:8080/redoc
- OpenAPI JSON: http://localhost:8080/openapi.json
All errors follow a consistent format:
{
"detail": "Error message describing what went wrong"
}200 OK- Success201 Created- Resource created successfully204 No Content- Success with no response body400 Bad Request- Invalid request data401 Unauthorized- Missing or invalid authentication403 Forbidden- Insufficient permissions404 Not Found- Resource not found429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error503 Service Unavailable- Service unhealthy
TOKEN=$(curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password"}' \
| jq -r '.access_token')curl http://localhost:8080/health | jqcurl http://localhost:8080/api/v1/devices \
-H "Authorization: Bearer $TOKEN" | jqcurl -X POST http://localhost:8080/api/v1/devices \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device_id": "test-plug-01",
"name": "Test Smart Plug",
"type": "smart_plug",
"manufacturer": "Test",
"capabilities": ["power_monitoring"]
}' | jqcurl http://localhost:8080/api/v1/devices/test-plug-01 \
-H "Authorization: Bearer $TOKEN" | jqcurl http://localhost:8080/metrics | grep aetherlens# Install dependencies
pip install -r requirements.txt
# Start the API server
uvicorn aetherlens.api.main:app --reload --host 0.0.0.0 --port 8080# Build and start all services
docker-compose up -d
# View logs
docker-compose logs -f aetherlens-api
# Stop services
docker-compose down| Metric | Target |
|---|---|
| API response time (p50) | <50ms |
| API response time (p95) | <200ms |
| API response time (p99) | <500ms |
| Requests per second | >1000 |
| Concurrent connections | >100 |
| Memory usage (idle) | <256MB |
| Startup time | <5s |
- All passwords are hashed using bcrypt
- JWT tokens expire after 1 hour (access) or 7 days (refresh)
- Rate limiting prevents abuse
- CORS is configured (update for production)
- All database queries use parameterized statements
- Request IDs enable request tracing
For issues or questions:
- GitHub Issues: https://github.com/aetherlens/home/issues
- Documentation: https://docs.aetherlens.io
- Discord: https://discord.gg/aetherlens