Skip to main content
The V0 API (/api/conversations) is deprecated and scheduled for removal on April 1, 2026. Please migrate to the V1 API as soon as possible.

Overview

This guide walks you through migrating from OpenHands V0 APIs to the new V1 APIs. We’ll take you step-by-step through a typical migration, showing exactly what changes and why.

What’s Different in V1?

The most important change: Conversations and Sandboxes are now decoupled. In V0, creating a conversation automatically created and managed the underlying sandbox (runtime environment). In V1, sandboxes are independent resources you can:
  • Pause and resume without losing state
  • Reuse across multiple conversations
  • Manage with explicit lifecycle controls
V1 also introduces two levels of API:
  • App Server API (app.all-hands.dev) - Manage conversations and sandboxes (this guide’s focus)
  • Agent Server API (per-sandbox URL) - Direct access to workspace and runtime operations
ThemeKey Result
Reliability61% reduction in system failures — eliminated entire classes of infrastructure errors
PerformanceLighter-weight runtime with co-located execution — removes inter-pod communication overhead
Developer ExperienceModern API patterns — dedicated search, filtering, batch operations, webhooks, and flexible sandbox controls
Reliability Details
  • 61% reduction in system-attributable failures (78.0 → 30.0 errors per 1k conversations)
  • Eliminated infrastructure errors from inter-pod communication
  • Event-sourced state enables replay-based recovery
Performance Details
  • Lighter-weight agent server reduces resource overhead
  • Independent sandbox lifecycle for better resource control
Developer Experience Details
  • Pause/resume sandboxes, explicit status tracking (STARTING, RUNNING, PAUSED, ERROR)
  • Dedicated search and count endpoints
  • Batch operations and enhanced filtering
  • Webhook support for lifecycle events
  • Stream conversation updates from creation

Migration Walkthrough

Follow along as we migrate a typical V0 integration to V1. Each step shows your existing V0 code and the V1 equivalent.

Step 1: Create and Start a Conversation

V0 Approach In V0, you called a single endpoint and got a conversation ID immediately:
curl -X POST "https://app.all-hands.dev/api/conversations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "initial_user_msg": "Check the README.md file",
    "repository": "yourusername/your-repo"
  }'
Response:
{
  "status": "ok",
  "conversation_id": "abc1234"
}
V1 Approach In V1, conversation startup is asynchronous—you get a start task that tracks initialization:
curl -X POST "https://app.all-hands.dev/api/v1/app-conversations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "initial_message": {
      "content": [{"type": "text", "text": "Check the README.md file"}]
    },
    "selected_repository": "yourusername/your-repo"
  }'
Response:
{
  "id": "start-task-uuid",
  "status": "STARTING",
  "conversation_id": null,
  "sandbox_id": null,
  "created_at": "2025-01-15T10:30:00Z"
}
Key Changes:
  • Endpoint: /api/conversations/api/v1/app-conversations
  • Field: initial_user_msg (string) → initial_message (object with content array)
  • Field: repositoryselected_repository
  • The conversation ID isn’t immediately available—see Step 2

Step 2: Track Conversation Startup

In V0, your conversation was ready immediately. In V1, you need to wait for initialization to complete. You have two options: Option A: Poll for Readiness
curl "https://app.all-hands.dev/api/v1/app-conversations/start-tasks?id={start_task_id}" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response when ready:
{
  "id": "start-task-uuid",
  "status": "READY",
  "conversation_id": "550e8400-e29b-41d4-a716-446655440000",
  "sandbox_id": "sandbox-abc123",
  "created_at": "2025-01-15T10:30:00Z"
}
The status field tells you where things stand:
  • STARTING → Still initializing, keep polling
  • READY → Conversation is ready, use conversation_id for subsequent calls
  • ERROR → Something went wrong, check the error field
Option B: Stream from the Start For real-time updates (recommended for user-facing apps), use the streaming endpoint:
curl -N "https://app.all-hands.dev/api/v1/app-conversations/stream-start" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "initial_message": {
      "content": [{"type": "text", "text": "Check the README.md file"}]
    },
    "selected_repository": "yourusername/your-repo"
  }'
This streams server-sent events as the conversation initializes and begins processing. You’ll receive status updates and can show progress to users immediately.
Streaming is recommended for user-facing applications where you want to show progress immediately rather than waiting for initialization to complete.

Step 3: Work with Events and Messages

Once your conversation is ready, here’s how to send messages and retrieve events. Sending Messages
curl -X POST "https://app.all-hands.dev/api/conversations/{id}/messages" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message": "Now check the package.json"}'
Retrieving Events V1 introduces dedicated search and count endpoints with enhanced filtering:
# Get all events
curl "https://app.all-hands.dev/api/conversations/{id}/events" \
  -H "Authorization: Bearer YOUR_API_KEY"

Step 4: Manage Sandbox Lifecycle

This is entirely new in V1. You now have explicit control over sandbox resources. Search for Your Sandboxes
curl "https://app.all-hands.dev/api/v1/sandboxes/search?limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
Pause a Sandbox (stop billing, preserve state)
curl -X POST "https://app.all-hands.dev/api/v1/sandboxes/{sandbox_id}/pause" \
  -H "Authorization: Bearer YOUR_API_KEY"
Resume a Sandbox (continue where you left off)
curl -X POST "https://app.all-hands.dev/api/v1/sandboxes/{sandbox_id}/resume" \
  -H "Authorization: Bearer YOUR_API_KEY"
Delete a Sandbox (clean up resources)
curl -X DELETE "https://app.all-hands.dev/api/v1/sandboxes/{sandbox_id}" \
  -H "Authorization: Bearer YOUR_API_KEY"
Sandbox Status Values:
  • STARTING - Sandbox is initializing
  • RUNNING - Sandbox is active and ready
  • PAUSED - Sandbox is suspended (no billing)
  • ERROR - Something went wrong
  • MISSING - Sandbox no longer exists

Step 5: Access the Agent Server (When Needed)

For direct workspace operations (file uploads, bash commands, git operations), you’ll use the Agent Server API. This runs on each sandbox and requires a different authentication method. Getting the Agent Server URL First, get your sandbox details:
curl "https://app.all-hands.dev/api/v1/sandboxes?id={sandbox_id}" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response:
{
  "id": "sandbox-abc123",
  "status": "RUNNING",
  "session_api_key": "session-key-xyz",
  "exposed_urls": {
    "AGENT_SERVER": "https://sandbox-abc123.runtime.all-hands.dev",
    "VSCODE": "https://vscode-abc123.runtime.all-hands.dev"
  }
}
Making Agent Server Calls Use the session_api_key with the X-Session-API-Key header:
# Execute a bash command
curl -X POST "https://sandbox-abc123.runtime.all-hands.dev/api/bash/execute_bash_command" \
  -H "X-Session-API-Key: session-key-xyz" \
  -H "Content-Type: application/json" \
  -d '{"command": "ls -la"}'

# Download a file
curl "https://sandbox-abc123.runtime.all-hands.dev/api/file/download/workspace/README.md" \
  -H "X-Session-API-Key: session-key-xyz"

# Upload a file
curl -X POST "https://sandbox-abc123.runtime.all-hands.dev/api/file/upload/workspace/config.json" \
  -H "X-Session-API-Key: session-key-xyz" \
  -F "file=@local-config.json"
The Agent Server’s OpenAPI spec is available at {agent_server_url}/openapi.json for complete endpoint documentation.

Step 6: Handle Files and Workspace

File operations have moved from the App Server to the Agent Server in V1.
V0 OperationV1 Equivalent
GET /api/conversations/{id}/list-filesAgent Server: POST /api/bash/execute_bash_command with ls
GET /api/conversations/{id}/select-fileAgent Server: GET /api/file/download/{path}
POST /api/conversations/{id}/upload-filesAgent Server: POST /api/file/upload/{path}
GET /api/conversations/{id}/zip-directoryAgent Server: GET /api/file/download/{path} for individual files
Example: List Files in Workspace
# Get Agent Server URL first (see Step 5), then:
curl -X POST "https://sandbox-abc123.runtime.all-hands.dev/api/bash/execute_bash_command" \
  -H "X-Session-API-Key: session-key-xyz" \
  -H "Content-Type: application/json" \
  -d '{"command": "find /workspace -type f -name \"*.py\" | head -20"}'
Alternative: Use the Agent SDK The OpenHands Agent SDK provides convenient methods that work with both V0 and V1:
from openhands import Workspace

workspace = Workspace(conversation_id="your-conversation-id")
files = workspace.list_files()
content = workspace.read_file("README.md")
workspace.write_file("output.txt", "Hello, world!")

Quick Reference: Endpoint Mapping

Use this section to look up specific endpoint mappings when you need them.

Conversation Lifecycle

OperationV0 EndpointV1 Endpoint
Create conversationPOST /api/conversationsPOST /api/v1/app-conversations
Start (streaming)POST /api/conversations/{id}/startPOST /api/v1/app-conversations/stream-start
Search conversationsGET /api/conversationsGET /api/v1/app-conversations/search
Get by IDGET /api/conversations/{id}GET /api/v1/app-conversations?id={id}
Get countN/AGET /api/v1/app-conversations/count
UpdatePATCH /api/conversations/{id}PATCH /api/v1/app-conversations/{id}
DeleteDELETE /api/conversations/{id}DELETE /api/v1/app-conversations/{id}

Events & Messages

OperationV0 EndpointV1 Endpoint
Send messagePOST /api/conversations/{id}/messagesPOST /api/v1/conversation/{id}/events
Get eventsGET /api/conversations/{id}/eventsGET /api/v1/conversation/{id}/events/search
Get event countN/AGET /api/v1/conversation/{id}/events/count
Batch get eventsN/AGET /api/v1/conversation/{id}/events

Sandbox Management (New in V1)

OperationV1 Endpoint
Create sandboxPOST /api/v1/sandboxes
Search sandboxesGET /api/v1/sandboxes/search
Get sandboxesGET /api/v1/sandboxes
PausePOST /api/v1/sandboxes/{id}/pause
ResumePOST /api/v1/sandboxes/{id}/resume
DeleteDELETE /api/v1/sandboxes/{id}

Development Tools

OperationV0 EndpointV1 Equivalent
Get VSCode URLGET /api/conversations/{id}/vscode-urlGet sandbox, find VSCODE in exposed_urls
Get web hostsGET /api/conversations/{id}/web-hostsGet sandbox, find AGENT_SERVER in exposed_urls

Health & Status (Unchanged)

OperationEndpoint
Health checkGET /health
Alive checkGET /alive
Ready checkGET /ready

Agent Server API Reference

The Agent Server runs on each sandbox and provides direct access to workspace operations.

Authentication

Use the session_api_key from your sandbox info with the X-Session-API-Key header.

Available Endpoints

EndpointDescription
POST /api/file/upload/{path}Upload files to workspace
GET /api/file/download/{path}Download individual files
GET /api/file/download-trajectory/{conversation_id}Download conversation trajectory
EndpointDescription
GET /api/git/changes/{path}Get git changes
GET /api/git/diff/{path}Get git diff
EndpointDescription
POST /api/bash/execute_bash_commandExecute bash command (blocking)
POST /api/bash/start_bash_commandStart bash command (async)
GET /api/bash/bash_events/searchSearch bash events
EndpointDescription
POST /api/conversations/{id}/eventsSend user message
GET /api/conversations/{id}/events/searchSearch events
GET /api/conversations/{id}/events/countCount events
POST /api/conversations/{id}/pausePause conversation
POST /api/conversations/{id}/runResume/run conversation
DELETE /api/conversations/{id}Delete conversation
EndpointDescription
GET /api/vscode/urlGet VSCode URL
GET /api/vscode/statusCheck VSCode status
GET /api/desktop/urlGet desktop URL
GET /api/tools/List available tools
The Agent Server requires an active (running) sandbox. For operations on paused or inactive sandboxes, use the App Server API.

Accessing Agent Server API Documentation

The Agent Server provides its own Swagger UI and OpenAPI specification, but you need a running sandbox to access them. Step 1: Get the Agent Server URL First, retrieve your sandbox info to get the Agent Server URL (see Step 5 above):
curl "https://app.all-hands.dev/api/v1/sandboxes?id={sandbox_id}" \
  -H "Authorization: Bearer YOUR_API_KEY"
From the response, extract the AGENT_SERVER URL from exposed_urls. Step 2: Access the Documentation Once you have the Agent Server URL, you can access:
ResourceURL
Swagger UI{agent_server_url}/docs
OpenAPI JSON{agent_server_url}/openapi.json
For example, if your Agent Server URL is https://sandbox-abc123.runtime.all-hands.dev:
# View the OpenAPI spec
curl "https://sandbox-abc123.runtime.all-hands.dev/openapi.json" \
  -H "X-Session-API-Key: session-key-xyz"

# Or open in browser for interactive Swagger UI:
# https://sandbox-abc123.runtime.all-hands.dev/docs
The Agent Server’s Swagger UI doesn’t require authentication to view, but you’ll need the X-Session-API-Key header to execute requests.

Known Gaps and Workarounds

Some V0 capabilities don’t have direct V1 App Server equivalents yet:
GapV0 EndpointWorkaround
Download workspace as zipGET /api/conversations/{id}/zip-directoryUse Agent Server to download individual files, or Agent SDK workspace.get_workspace_zip()
Get trajectory (inactive runtime)GET /api/conversations/{id}/trajectoryTrajectory available while sandbox is active via Agent Server
List workspace filesGET /api/conversations/{id}/list-filesUse Agent Server POST /api/bash/execute_bash_command with ls, or Agent SDK workspace.list_files()

Authentication Summary

APIAuthentication
App Server (both V0 and V1)API key via Authorization: Bearer YOUR_API_KEY header
Agent ServerSession API key via X-Session-API-Key: {session_api_key} header
API keys are created via the settings page or /api/keys endpoint and work for both V0 and V1 App Server APIs.

Additional Resources