Dev envs for humans and agents.
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.
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
Install the SDK from npm:
npm install @latitudesh/devboxCreate 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)All API requests require a service token sent as a header:
X-Provider-TokenstringrequiredProvider token for API authentication
AuthorizationstringUser bearer token: Bearer <token>
X-Codex-TokenstringCodex token to inject into the devbox (create only)
X-Claude-TokenstringClaude token to inject into the devbox (create only)
/api/v1/devboxesCreate a new devbox. Returns 202 with the devbox in 'requested' state.
Request body
namestringrequiredDisplay name for the devbox
planstringSize plan. Default: "small"
repositorystringSingle repository URL (legacy)
branchstringBranch to clone. Default: "main"
repositoriesDevboxRepositoryRequest[]List of repositories to mount
credential_profileobjectToken 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_secondsnumberHard 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: '...',
})/api/v1/devboxesList all devboxes for the current user.
SDK
const devboxes = await client.devboxes.list()/api/v1/devboxes/:idGet a single devbox by ID.
SDK
const devbox = await client.devboxes.get("devbox-id")/api/v1/devboxes/:idDestroy a devbox. Returns 204.
SDK
await client.devboxes.delete("devbox-id")/api/v1/devboxes/:id/operationsList 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/api/v1/devboxes/:id/access/sessionCreate an SSH access session. Returns 201 with session credentials and SSH connection details.
Response
session_idstringrequiredUnique session identifier
expires_atdatetimerequiredSession expiration timestamp
commandstringrequiredReady-to-use SSH command
sshSshAccessResponserequiredSSH 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/api/v1/devboxes/:id/access/sessionsList active exec sessions for a devbox.
SDK
const sessions = await client.devboxes.listSessions("devbox-id")/api/v1/devboxes/:id/access/session/:session_idRevoke an access session. Returns 204.
SDK
await client.devboxes.revokeSession("devbox-id", "session-id")/api/v1/devboxes/:id/repositoriesList repositories mounted in a devbox, including clone status.
SDK
const repos = await client.devboxes.listRepositories("devbox-id")/api/v1/users/meGet the current user's profile.
SDK
const profile = await client.users.getProfile()/api/v1/users/me/ssh-keySet or update the user's SSH public key. Returns 204.
SDK
await client.users.setSshKey("ssh-ed25519 AAAA...")/api/v1/users/me/ssh-keyRemove the user's SSH key. Returns 204.
SDK
await client.users.deleteSshKey()/api/v1/integrations/github/connectStart the GitHub OAuth flow. Returns an authorization URL to redirect the user.
SDK
const oauth = await client.github.startOAuth("https://app.example.com/callback")/api/v1/integrations/github/connectionGet the current GitHub connection, or null if not connected.
SDK
const conn = await client.github.getConnection()/api/v1/integrations/github/connectionRevoke the GitHub connection. Returns 204.
SDK
await client.github.disconnect()/api/v1/integrations/github/reposList accessible GitHub repositories for the connected user.
SDK
const repos = await client.github.listRepos()/api/v1/integrations/github/orgsList GitHub organizations for the connected user.
SDK
const orgs = await client.github.listOrgs()/api/v1/integrations/github/org-grantsUpdate which organizations grant access to their repositories.
SDK
await client.github.updateOrgGrants(["my-org", "other-org"])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.