# API Reference Complete reference for the Tyto REST API. ## Base URL ``` http://localhost:8080/api/v1 ``` ## Authentication Most endpoints require authentication via Bearer token: ```bash curl -H "Authorization: Bearer " http://localhost:8080/api/v1/... ``` ### Obtain Token ```bash curl -X POST http://localhost:8080/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "password"}' ``` Response: ```json { "token": "abc123...", "user": { "id": "user-id", "username": "admin", "email": "admin@example.com", "roles": ["admin"] }, "expires_at": "2024-01-16T10:30:00Z" } ``` --- ## Health Check ### GET /health Check server health. **Authentication**: Not required **Response**: ```json { "status": "ok", "version": "1.0.0", "uptime": 3600 } ``` --- ## Authentication ### POST /api/v1/auth/login Authenticate and obtain session token. **Request**: ```json { "username": "admin", "password": "password" } ``` **Response**: ```json { "token": "abc123...", "user": { "id": "uuid", "username": "admin", "email": "admin@example.com", "roles": ["admin"], "permissions": ["*"] }, "expires_at": "2024-01-16T10:30:00Z" } ``` ### POST /api/v1/auth/logout Invalidate current session. **Response**: `204 No Content` ### POST /api/v1/auth/register Register new user (if enabled). **Request**: ```json { "username": "newuser", "password": "password123", "email": "user@example.com" } ``` ### GET /api/v1/auth/me Get current user info. **Response**: ```json { "id": "uuid", "username": "admin", "email": "admin@example.com", "roles": ["admin"], "permissions": ["*"], "auth_provider": "local", "last_login": "2024-01-15T10:30:00Z" } ``` ### PUT /api/v1/auth/me Update current user profile. **Request**: ```json { "email": "newemail@example.com" } ``` ### PUT /api/v1/auth/me/password Change password. **Request**: ```json { "current_password": "old-password", "new_password": "new-password" } ``` --- ## Metrics ### GET /api/v1/stream Server-Sent Events stream of real-time metrics. **Query Parameters**: | Parameter | Type | Description | |-----------|------|-------------| | `agent_id` | string | Filter by agent (multi-device mode) | **Response**: SSE stream ``` event: metrics data: {"timestamp":"2024-01-15T10:30:00Z","cpu":{...},"memory":{...}} event: metrics data: {"timestamp":"2024-01-15T10:30:05Z","cpu":{...},"memory":{...}} ``` **Metrics Structure**: ```json { "timestamp": "2024-01-15T10:30:00Z", "system": { "hostname": "server-01", "kernel": "6.1.0-generic", "uptime": 86400, "architecture": "x86_64" }, "cpu": { "cores": [ {"id": 0, "usage": 15.5, "frequency": 3600} ], "totalUsage": 15.5, "loadAverage": {"one": 0.5, "five": 0.4, "fifteen": 0.3} }, "memory": { "total": 16000000000, "used": 8000000000, "free": 4000000000, "available": 10000000000, "buffers": 1000000000, "cached": 3000000000, "swapTotal": 4000000000, "swapUsed": 0 }, "disk": { "mounts": [ { "device": "/dev/sda1", "mountpoint": "/", "fstype": "ext4", "total": 500000000000, "used": 100000000000, "free": 400000000000 } ], "io": [ {"device": "sda", "readBytes": 1000000, "writeBytes": 500000} ] }, "network": { "interfaces": [ { "name": "eth0", "ipv4": "192.168.1.100", "ipv6": "fe80::1", "rxBytes": 1000000000, "txBytes": 500000000, "rxRate": 10000, "txRate": 5000 } ], "connectionCount": 42 }, "processes": { "topByCpu": [...], "topByMemory": [...], "total": 200 }, "temperature": { "sensors": [ {"name": "Core 0", "value": 45.0, "high": 80.0, "critical": 100.0} ] }, "gpu": { "available": true, "gpus": [ { "index": 0, "name": "NVIDIA GeForce RTX 3080", "vendor": "nvidia", "utilization": 45, "memoryUsed": 4000000000, "memoryTotal": 10000000000, "temperature": 65.0, "powerWatts": 220.0 } ] }, "docker": { "available": true, "containers": [ {"id": "abc123", "name": "nginx", "status": "running", "cpu": 0.5, "memory": 50000000} ] }, "systemd": { "available": true, "services": [ {"name": "nginx.service", "state": "active", "subState": "running"} ] } } ``` ### GET /api/v1/history Get historical metrics. **Query Parameters**: | Parameter | Type | Description | |-----------|------|-------------| | `from` | string | Start time (ISO 8601) | | `to` | string | End time (ISO 8601) | | `resolution` | string | `raw`, `1m`, `5m`, `1h` | | `agent_id` | string | Filter by agent | **Response**: ```json { "from": "2024-01-15T09:30:00Z", "to": "2024-01-15T10:30:00Z", "resolution": "1m", "data": [ { "timestamp": "2024-01-15T09:30:00Z", "cpu": {"avg": 15.0, "min": 10.0, "max": 25.0}, "memory": {"avg": 50.0, "min": 48.0, "max": 52.0} } ] } ``` ### GET /api/v1/export/metrics Export current metrics. **Query Parameters**: | Parameter | Type | Description | |-----------|------|-------------| | `format` | string | `json` or `csv` | --- ## Processes ### GET /api/v1/processes/:pid Get process details. **Response**: ```json { "pid": 1234, "name": "nginx", "cmdline": "/usr/sbin/nginx -g daemon off;", "user": "www-data", "state": "S", "cpu": 0.5, "memory": 50000000, "threads": 4, "startTime": "2024-01-15T08:00:00Z" } ``` ### POST /api/v1/processes/:pid/signal Send signal to process. **Request**: ```json { "signal": 15 } ``` **Common Signals**: | Signal | Number | Description | |--------|--------|-------------| | SIGTERM | 15 | Graceful termination | | SIGKILL | 9 | Force kill | | SIGSTOP | 19 | Pause process | | SIGCONT | 18 | Resume process | --- ## Alerts ### GET /api/v1/alerts Get current alerts. **Response**: ```json { "alerts": [ { "id": "alert-1", "type": "cpu", "level": "warning", "value": 85.0, "threshold": 80.0, "agent_id": "server-01", "created_at": "2024-01-15T10:30:00Z", "acknowledged": false } ], "config": { "cpu": {"warning": 80, "critical": 95}, "memory": {"warning": 85, "critical": 95}, "disk": {"warning": 80, "critical": 90} } } ``` ### POST /api/v1/alerts/config Update alert thresholds. **Request**: ```json { "cpu": {"warning": 80, "critical": 95}, "memory": {"warning": 85, "critical": 95}, "disk": {"warning": 80, "critical": 90} } ``` ### POST /api/v1/alerts/:id/acknowledge Acknowledge an alert. --- ## Agents ### GET /api/v1/agents List all agents. **Response**: ```json { "agents": [ { "id": "web-server-01", "name": "Web Server", "hostname": "web-server", "status": "online", "architecture": "amd64", "os": "linux", "last_seen": "2024-01-15T10:30:00Z", "registered_at": "2024-01-01T00:00:00Z" } ] } ``` ### GET /api/v1/agents/:id Get agent details. ### POST /api/v1/agents Add agent manually. **Request**: ```json { "id": "new-agent", "name": "New Agent" } ``` ### DELETE /api/v1/agents/:id Remove agent. ### POST /api/v1/agents/:id/revoke Revoke agent certificate. ### GET /api/v1/agents/pending List pending agent registrations. ### POST /api/v1/agents/pending/:id/approve Approve pending agent. ### POST /api/v1/agents/pending/:id/reject Reject pending agent. --- ## Users ### GET /api/v1/users List all users. **Response**: ```json { "users": [ { "id": "uuid", "username": "admin", "email": "admin@example.com", "roles": ["admin"], "auth_provider": "local", "disabled": false, "created_at": "2024-01-01T00:00:00Z", "last_login": "2024-01-15T10:30:00Z" } ] } ``` ### POST /api/v1/users Create user. **Request**: ```json { "username": "newuser", "password": "password123", "email": "user@example.com", "roles": ["operator"] } ``` ### GET /api/v1/users/:id Get user details. ### PUT /api/v1/users/:id Update user. **Request**: ```json { "email": "newemail@example.com", "roles": ["operator", "viewer"] } ``` ### DELETE /api/v1/users/:id Disable user (soft delete). ### PUT /api/v1/users/:id/password Reset user password. **Request**: ```json { "new_password": "temporary-password" } ``` --- ## Roles ### GET /api/v1/roles List all roles. **Response**: ```json { "roles": [ { "id": "admin", "name": "Administrator", "description": "Full system access", "permissions": ["*"], "is_system": true } ] } ``` ### POST /api/v1/roles Create custom role. **Request**: ```json { "name": "Alert Manager", "description": "Can manage alerts only", "permissions": ["dashboard:view", "alerts:*"] } ``` ### PUT /api/v1/roles/:id Update role. ### DELETE /api/v1/roles/:id Delete custom role (system roles cannot be deleted). --- ## Logs ### GET /api/v1/logs Query logs. **Query Parameters**: | Parameter | Type | Description | |-----------|------|-------------| | `agent_id` | string | Filter by agent | | `source` | string | Filter by source (journal, file, docker) | | `source_name` | string | Filter by source name | | `level` | string | Comma-separated levels | | `q` | string | Full-text search | | `from` | string | Start time (ISO 8601) | | `to` | string | End time (ISO 8601) | | `limit` | int | Max results (default 100) | | `offset` | int | Pagination offset | **Response**: ```json { "entries": [ { "id": "log-1", "timestamp": "2024-01-15T10:30:00Z", "agent_id": "web-server-01", "source": "journal", "source_name": "nginx.service", "level": "error", "message": "Connection refused", "fields": {"pid": "1234"} } ], "total": 150 } ``` ### GET /api/v1/logs/stream SSE stream of live logs. **Query Parameters**: Same as `/api/v1/logs` --- ## Settings ### POST /api/v1/settings/refresh Update refresh interval. **Request**: ```json { "interval": 5 } ``` --- ## Error Responses All errors follow this format: ```json { "error": "Error message", "code": "ERROR_CODE", "details": {} } ``` **HTTP Status Codes**: | Code | Description | |------|-------------| | 400 | Bad Request - Invalid input | | 401 | Unauthorized - Missing/invalid token | | 403 | Forbidden - Insufficient permissions | | 404 | Not Found - Resource doesn't exist | | 500 | Internal Server Error |