devbox
dashboarddocs

docs

Dev envs for humans and agents.

Overview

Devbox is a sandbox provisioning service by Latitude.sh. It creates on-demand development environments backed by cloud infrastructure, with SSH access, GitHub repo cloning, and optional AI credential injection for tools like Claude and Codex.

Use the REST API or the @latitudesh/devbox TypeScript SDK to create, manage, and connect to devboxes programmatically.

See security model for details on how credentials are handled.

Dashboard

Devbox includes a web dashboard for managing your environments without writing code. Create, monitor, and destroy devboxes, connect your GitHub account, and manage SSH keys.

Open dashboard

Create and manage devboxes from the web UI

SDK quickstart

Install the SDK from npm:

npm install @latitudesh/devbox

Create a client and spin up a devbox:

import { DevboxClient } from '@latitudesh/devbox'

const client = new DevboxClient({
  providerToken: process.env.PROVIDER_TOKEN,
  userToken: process.env.USER_TOKEN,       // optional
})

// Create a devbox with Claude token injection
const devbox = await client.devboxes.create({
  name: 'my-sandbox',
  credential_profile: { inject_claude_token: true },
}, { claudeToken: process.env.CLAUDE_TOKEN })

// Wait for it to be ready (polls until state === 'ready')
const ready = await client.devboxes.waitForReady(devbox.id)

// Get SSH session
const session = await client.devboxes.createSession(ready.id)
console.log(session.command)

Authentication

All API requests require a service token sent as a header:

X-Provider-Tokenstringrequired

Provider token for API authentication

Authorizationstring

User bearer token: Bearer <token>

X-Codex-Tokenstring

Codex token to inject into the devbox (create only)

X-Claude-Tokenstring

Claude token to inject into the devbox (create only)

Devboxes

POST/api/v1/devboxes

Create a new devbox. Returns 202 with the devbox in 'requested' state.

Request body

namestringrequired

Display name for the devbox

planstring

Size plan. Default: "small"

repositorystring

Single repository URL (legacy)

branchstring

Branch to clone. Default: "main"

repositoriesDevboxRepositoryRequest[]

List of repositories to mount

credential_profileobject

Token injection flags: inject_codex_token, inject_claude_token

envRecord<string, string>

Environment variables to inject into the devbox. Keys must match ^[A-Z_][A-Z0-9_]*$ (up to 64 keys, 32 KiB per value). Stored encrypted at rest and available to setup_commands and the eventual session.

setup_commandsstring[]

Shell commands run sequentially inside the devbox after clone_repositories succeeds. First non-zero exit fails provisioning; the captured stdout/stderr tail is exposed via listOperations. Up to 32 commands, 4 KiB each.

setup_timeout_secondsnumber

Hard ceiling for the setup_commands step. Bounded 30-3600, default 900.

SDK

const devbox = await client.devboxes.create({
  name: 'my-sandbox',
  repositories: [{
    repo_id: 12345,
    full_name: 'org/repo',
    ref: 'main',
    target_path: '/workspace/repo',
  }],
  env: {
    DATABASE_URL: 'postgres://...',
    NODE_ENV: 'development',
  },
  setup_commands: [
    'cd /workspace/repo && npm install',
    'cd /workspace/repo && npm run build',
  ],
  setup_timeout_seconds: 600,
  credential_profile: {
    inject_claude_token: true,
    inject_codex_token: true,
  },
}, {
  claudeToken: '...',
  codexToken: '...',
})
GET/api/v1/devboxes

List all devboxes for the current user.

SDK

const devboxes = await client.devboxes.list()
GET/api/v1/devboxes/:id

Get a single devbox by ID.

SDK

const devbox = await client.devboxes.get("devbox-id")
DELETE/api/v1/devboxes/:id

Destroy a devbox. Returns 204.

SDK

await client.devboxes.delete("devbox-id")
GET/api/v1/devboxes/:id/operations

List provisioning operations for a devbox. Each operation represents a step: provision, inject_credentials, clone_repositories, run_setup_commands, publish_access.

SDK

const ops = await client.devboxes.listOperations("devbox-id")

Polling helper

The SDK provides waitForReady() which polls until the devbox reaches the ready state or a terminal state (failed, destroyed, stopped).

const ready = await client.devboxes.waitForReady("devbox-id", {
  intervalMs: 3000,   // default
  timeoutMs: 120000,  // default
})

Devbox states

requestedprovisioningreadystoppeddestroyedfailed

Sessions

POST/api/v1/devboxes/:id/access/session

Create an SSH access session. Returns 201 with session credentials and SSH connection details.

Response

session_idstringrequired

Unique session identifier

expires_atdatetimerequired

Session expiration timestamp

commandstringrequired

Ready-to-use SSH command

sshSshAccessResponserequired

SSH connection details: host, port, username, workspace_path

SDK

const session = await client.devboxes.createSession("devbox-id")
console.log(session.command)
// ssh user@host -p 2222
GET/api/v1/devboxes/:id/access/sessions

List active exec sessions for a devbox.

SDK

const sessions = await client.devboxes.listSessions("devbox-id")
DELETE/api/v1/devboxes/:id/access/session/:session_id

Revoke an access session. Returns 204.

SDK

await client.devboxes.revokeSession("devbox-id", "session-id")

Repositories

GET/api/v1/devboxes/:id/repositories

List repositories mounted in a devbox, including clone status.

SDK

const repos = await client.devboxes.listRepositories("devbox-id")

Users

GET/api/v1/users/me

Get the current user's profile.

SDK

const profile = await client.users.getProfile()
PUT/api/v1/users/me/ssh-key

Set or update the user's SSH public key. Returns 204.

SDK

await client.users.setSshKey("ssh-ed25519 AAAA...")
DELETE/api/v1/users/me/ssh-key

Remove the user's SSH key. Returns 204.

SDK

await client.users.deleteSshKey()

GitHub

POST/api/v1/integrations/github/connect

Start the GitHub OAuth flow. Returns an authorization URL to redirect the user.

SDK

const oauth = await client.github.startOAuth("https://app.example.com/callback")
GET/api/v1/integrations/github/connection

Get the current GitHub connection, or null if not connected.

SDK

const conn = await client.github.getConnection()
DELETE/api/v1/integrations/github/connection

Revoke the GitHub connection. Returns 204.

SDK

await client.github.disconnect()
GET/api/v1/integrations/github/repos

List accessible GitHub repositories for the connected user.

SDK

const repos = await client.github.listRepos()
GET/api/v1/integrations/github/orgs

List GitHub organizations for the connected user.

SDK

const orgs = await client.github.listOrgs()
PUT/api/v1/integrations/github/org-grants

Update which organizations grant access to their repositories.

SDK

await client.github.updateOrgGrants(["my-org", "other-org"])

Security model

All credentials are encrypted at rest using AES (Fernet) and handled with minimal retention.

AI credentials (Claude & Codex tokens)

Tokens are encrypted and stored only during provisioning. Once the devbox is ready, they are injected as environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY) and immediately deleted from our database.

GitHub OAuth tokens

Stored encrypted at rest for ongoing repository access. Used server-side only to clone repos at devbox creation time — never exposed to the devbox or returned via the API. Deleted when the user disconnects GitHub.

User authentication

Bearer tokens from the Authorization header are used to identify the user and forwarded to upstream services. They are not persisted in our database.