# REST API Contract Base path: `/api/v1` All responses are JSON. ## Authentication ### `POST /auth/login` Request: ```json { "username": "alice", "password": "secret-password" } ``` Response: ```json { "access_token": "jwt", "refresh_token": "opaque-token", "expires_in": 900, "user": { "id": "uuid", "username": "alice", "display_name": "Alice", "role": "admin" } } ``` ### `POST /auth/refresh` Request: ```json { "refresh_token": "opaque-token" } ``` ### `POST /auth/logout` Request: ```json { "refresh_token": "opaque-token" } ``` ### `GET /auth/me` Returns the authenticated user and role. ## User Self-Service ### `GET /me/devices` Returns the current user devices. ### `GET /me/profile` Returns profile metadata for the current active device when the client needs to resync. ## Device Enrollment and Provisioning ### `POST /devices/enroll` Request: ```json { "name": "Alice MacBook Pro", "platform": "macos", "os_version": "14.4", "app_version": "0.1.0", "device_fingerprint": "sha256:...", "public_key": "base64-wireguard-public-key" } ``` Response: ```json { "device": { "id": "uuid", "name": "Alice MacBook Pro", "status": "active" }, "peer": { "assigned_ip": "100.96.0.10/32", "dns_servers": ["10.20.0.53"], "allowed_ips": ["172.16.10.0/24"], "gateway": { "id": "uuid", "name": "primary-gateway", "endpoint": "vpn.example.com:51820", "public_key": "gateway-public-key" }, "profile_revision": 1 }, "profile": { "format": "wireguard", "content": "[Interface]\n..." }, "resources": [ { "type": "cidr", "value": "172.16.10.0/24", "label": "Private subnet" } ] } ``` ### `GET /devices/{deviceId}/profile` Admin-only debug endpoint for rendered config retrieval. ### `POST /devices/{deviceId}/rotate` Rotates the device profile revision and forces reprovisioning. ### `POST /devices/{deviceId}/revoke` Revokes the device and removes it from future gateway sync output. ### `POST /devices/{deviceId}/heartbeat` Optional client status sync for last-seen and runtime metadata. ## Connection Metadata ### `GET /connection/status` Returns assigned IP, latest sync time, and effective allowed resources for the current authenticated device session. ## Admin: Users ### `GET /admin/users` ### `POST /admin/users` ### `GET /admin/users/{id}` ### `PATCH /admin/users/{id}` ### `POST /admin/users/{id}/disable` ### `POST /admin/users/{id}/enable` ### `POST /admin/users/{id}/password` ## Admin: Devices ### `GET /admin/devices` ### `GET /admin/devices/{id}` ### `PATCH /admin/devices/{id}` ### `POST /admin/devices/{id}/revoke` ### `POST /admin/devices/{id}/rotate` ## Admin: Policies ### `GET /admin/policies` ### `POST /admin/policies` ### `GET /admin/policies/{id}` ### `PATCH /admin/policies/{id}` ### `DELETE /admin/policies/{id}` Policy create request: ```json { "name": "Finance subnet access", "description": "Access for finance team", "priority": 100, "effect": "allow", "full_tunnel": false, "destinations": [ "172.16.20.0/24", "172.16.21.10/32" ], "targets": [ { "type": "user", "id": "uuid" } ] } ``` ## Admin: Gateways ### `GET /admin/gateways` ### `POST /admin/gateways` ### `GET /admin/gateways/{id}` ### `PATCH /admin/gateways/{id}` ### `GET /admin/gateways/{id}/sync` The sync endpoint returns the peer and firewall bundle consumed by the gateway helper. ## Admin: Audit ### `GET /admin/audit-logs` Query params: - `event_type` - `entity_type` - `status` - `page` - `page_size` ## Error Format ```json { "error": { "code": "validation_error", "message": "public_key is required" } } ```