REST API
The public API is served by a Cloudflare Worker at https://api.clawmobile.cloud.
All /api/* routes require a bearer token; /auth/* issues them.
Auth
POST /auth/signup
Request a magic link. Body: { "email": string, "invite_code?": string }.
While invites are required, a valid invite_code must be supplied. In dev (no
email provider configured) the response includes magic_token directly.
GET /auth/verify?token=<magic_token>
Exchange a magic-link token for credentials.
Returns { "access_token": string, "refresh_token": string }.
POST /auth/refresh
Body: { "refresh_token": string } → { "access_token": string }.
Sessions
POST /api/sessions
Allocate a device and start a session. Subject to rate limits (1 active
session, 5 per hour). Returns a SessionResponse with id, status, and
stream_url.
GET /api/sessions/:id
Fetch a session’s current state.
DELETE /api/sessions/:id
End a session. Skills sync to R2, the container is destroyed, the workspace is wiped.
GET /api/sessions/:id/stream
Server-Sent Events for allocation + lifecycle progress
(redroid_starting → adb_handshake → gateway_starting → active →
ended / error).
Skills
GET /api/skills
List your skills. Returns { "skills": SkillIndex[] }.
GET /api/skills/:name
Skill detail: { "skill": SkillIndex, "versions": SkillVersion[], "runs": EvalRun[] }.
GET /api/skills/:name/share
Generate a presigned, time-limited share URL:
{ "url": string, "expires_in": number }. Returns 503 if sharing isn’t
configured.
Account
GET /api/account/me
Your profile (never includes the API key hash).
PATCH /api/account/me
Update display_name, recording_opt_in, or session_timeout_min.
POST /api/account/me/api-key
Generate (or regenerate) your API key. The plaintext key is shown once in the response — store it immediately.
Errors
Errors are JSON: { "error": string, "code?": string } with a conventional HTTP
status (401 unauthenticated, 403 forbidden, 404 not found, 429 rate
limited, 503 capacity/feature unavailable).
Next: FAQ