REST API
HTTP REST API endpoints for authentication, device management, sessions, and auto-updates.
Auth Endpoints (Public)
POST /auth/signup
Content-Type: application/json
{ "email": "user@example.com", "password": "secret" }
→ 200 OK
{ "accessToken": "JWT", "refreshToken": "JWT" }POST /auth/login
Same request/response format as signup.
POST /auth/refresh
Content-Type: application/json
{ "refreshToken": "JWT" }
→ 200 OK
{ "accessToken": "JWT", "refreshToken": "JWT" }POST /auth/forgot-password
Sends a 6-digit reset code to the user's email via Resend. Always returns success to prevent email enumeration. Rate limited to 1 request per minute per email.
Content-Type: application/json
{ "email": "user@example.com" }
→ 200 OK
{ "message": "If an account exists, a reset code has been sent" }
→ 503 Service Unavailable (if RESEND_API_KEY not configured)
{ "error": "Email service not configured" }POST /auth/reset-password
Validates the 6-digit code and updates the password. Returns JWT tokens on success (auto-login). Code expires after 1 hour.
Content-Type: application/json
{ "email": "user@example.com", "code": "123456", "password": "newpassword" }
→ 200 OK
{ "accessToken": "JWT", "refreshToken": "JWT" }
→ 400 Bad Request
{ "error": "Invalid or expired reset code" }Device Endpoints (Authenticated)
All device endpoints require Authorization: Bearer <JWT> header.
GET /devices
List all devices registered to the authenticated user.
POST /devices
Register a new device.
DELETE /devices/:deviceId
Remove a device.
POST /devices/:deviceId/heartbeat
Device keepalive.
POST /devices/:deviceId/offline
Mark device as offline.
Session Endpoints (Authenticated)
GET /devices/:deviceId/sessions
List sessions for a device.
POST /devices/:deviceId/sessions
Register a new session on a device.
DELETE /sessions/:sessionId
Delete a session.
PATCH /sessions/:sessionId
No-op — session metadata is now delivered E2E encrypted via Device WS. This endpoint exists for backward compatibility.
WebSocket Endpoints (Authenticated)
GET /devices/:deviceId/ws
Device-level WebSocket. Auth via ?token=JWT query param or first-message auth JSON.
GET /sessions/:sessionId/ws
Session-level WebSocket. Auth via ?token=JWT query param or first-message auth JSON.
Subscription gate: On hosted relays (POLAR_WEBHOOK_SECRET set), free-tier users receive HTTP 403 with { code: "RELAY_UPGRADE_REQUIRED" }. Share token viewers (?share_token=...) bypass the gate. Self-hosted relays skip all plan checks.
| Close Code | Meaning |
|---|---|
4403 | Relay access requires a Pro plan |
TURN Credentials (Authenticated)
GET /turn-credentials
Returns ICE server configuration including TURN credentials (if configured).
Authorization: Bearer <token>
→ 200 OK
{ "iceServers": [{ "urls": ["turn:..."], "username": "...", "credential": "..." }] }
→ 503 Service Unavailable (if TURN not configured)
{ "error": "TURN not configured" }