Reference

Desktop API

Desktop API

Crabfleet exposes desktop identity, private discovery, host registration, and an opaque RFB relay. JSON endpoints return structured errors with HTTP status codes. JSON request bodies must be objects; null, arrays, and primitive roots return 400 before fields are processed. Native request bodies are limited to 1 KiB.

#Browser identity

Malformed percent-encoded cookie values are ignored independently; valid cookies remain usable for sign-in, authenticated requests, and logout. Malformed percent encoding in /native/link/:code returns 400 before looking up the authorization link.

MethodRouteResult
GET/api/authAvailable authentication methods and public deployment configuration
GET/login/githubStart GitHub OAuth
GET/auth/github/callbackComplete OAuth and set the browser session
POST/api/login/tokenOwner recovery login with { "token": "…" }
POST/api/logoutDelete the current browser session
GET/api/sessionAuthenticated user and authentication methods
GET/api/fleetPrivate desktop discovery
GET / POST/api/admin/allowOwner-only allowlist read/update; POST accepts value and role
DELETE/api/admin/allow/:valueOwner-only removal of an encoded allowlist value

#Native device authorization

POST /api/native/v1/auth/device accepts clientName and optional scope. The default is fleet:read; connectors explicitly request desktop:publish. It returns deviceCode, verificationUri, expiresAt, and intervalSeconds.

Open verificationUri in a signed-in browser and approve the device. Poll POST /api/native/v1/auth/token with { "deviceCode": "…" }. Pending responses use 202; polling too quickly returns 429 with retry-after. Approval returns accessToken, tokenType, expiresAt, and user. Store the token securely for that deployment.

Approval and completion pages adapt to phone screens; the link can be opened on another device signed into the same deployment. GET never approves a device. POST requires the authenticated browser identity and exact public origin, plus the link-bound CSRF cookie for cookie-authenticated sessions. Expired or already-used links return 410 with an HTML recovery page. An unauthenticated deployment without GitHub login returns 401 with a link to sign in.

Each GitHub-backed native request allows up to 10 seconds for GitHub membership refresh, including team pagination. A timeout returns a retryable 503 without revoking the native credential.

MethodRouteAuthorization
GET/api/native/v1/sessionNative bearer; returns user and deployment
GET/api/native/v1/fleetfleet:read; returns private desktop discovery
DELETE/api/native/v1/auth/tokenRevoke the presented native bearer
GET / POST/native/link/:codeBrowser-authenticated approval with origin and confirmation checks

The fleet envelope contains generatedAt, registryAvailable, desktopHosts, canonicalUrl, and productUrl. For released Mac clients, it also retains sessions: [] and totals: { "active": 0, "sessions": 0, "vnc": 0 }. These legacy counters describe retired workspace sessions; use desktopHosts.length for the desktop count. There are no workspace sessions or workspace VNC grants.

Each desktop contains id, owner, name, address, port, relayOnly, quicPort, quicCertHash, webtransport, relayCapable, createdAt, and updatedAt. Times are Unix milliseconds. Ownership secrets are omitted from discovery responses.

#Host registration

Browser-authenticated Mac publication uses the routes below. A native viewer's fleet:read token is a discovery credential and does not authorize host registration. The Mac publisher currently receives its browser session through launch configuration; Linux uses the separate connector API.

MethodRouteAction
PUT/api/desktop-hosts/:idRegister/refresh a desktop
POST/api/desktop-hosts/:id?recover=1Recover ownership using body publicationID
DELETE/api/desktop-hosts/:idRemove the owned publication

Registration accepts name, address, port, optional quicPort and quicCertHash, optional webtransport, and optional relayOnly. Direct addresses must be Tailscale IPv4 addresses. A relay-only host requires token ownership.

Use x-crabfleet-ownership-mode: token-v1 and a durable x-crabfleet-publication-id to obtain an ownershipToken. Keep both private. Removal uses x-crabfleet-ownership-token. Publication retries and recovery preserve the existing ownership fences; an older publisher cannot remove a replacement.

#Linux connector

These routes require a desktop:publish bearer:

MethodRouteAction
GET/api/connector/v1/sessionValidate the connector identity
POST/api/connector/v1/auth/renewRenew current publication authorization
PUT/api/connector/v1/desktop-hosts/:idPublish with x-crabfleet-publication-id; token ownership is required
POST/api/connector/v1/desktop-hosts/:id/recoverRecover ownership with the publication ID header
DELETE/api/connector/v1/desktop-hosts/:idRemove with x-crabfleet-ownership-token

#VNC relay

GET /api/desktop-hosts/:id/relay/host upgrades to WebSocket after verifying the host's ownership token. GET /api/desktop-hosts/:id/relay/viewer upgrades after checking the browser identity owns that desktop and validating any browser Origin header.

The relay transports opaque RFB bytes with bounded queues and deadline-aware endpoint behavior. It does not expose host ownership credentials or store video. Direct VNC authentication remains separate; RFB None is allowed only inside an ownership-authenticated relay publication.