For the available API endpoints, refer to the
OpenHands API Reference.
Obtaining an API Key
To use the OpenHands Cloud API, you’ll need to generate an API key:
- Log in to your OpenHands Cloud account.
- Navigate to the Settings > API Keys page.
- Click
Create API Key.
- Give your key a descriptive name (Example: “Development” or “Production”) and select
Create.
- Copy the generated API key and store it securely. It will only be shown once.
API Usage Example (V1)
Starting a New Conversation
To start a new conversation with OpenHands to perform a task,
make a POST request to the V1 app-conversations endpoint.
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 whether there is any incorrect information in the README.md file and send a PR to fix it if so."}]
},
"selected_repository": "yourusername/your-repo"
}'
import requests
api_key = "YOUR_API_KEY"
url = "https://app.all-hands.dev/api/v1/app-conversations"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
data = {
"initial_message": {
"content": [{"type": "text", "text": "Check whether there is any incorrect information in the README.md file and send a PR to fix it if so."}]
},
"selected_repository": "yourusername/your-repo"
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
# The response contains a start task with the conversation ID
conversation_id = result.get("app_conversation_id") or result.get("id")
print(f"Conversation Link: https://app.all-hands.dev/conversations/{conversation_id}")
print(f"Status: {result['status']}")
const apiKey = "YOUR_API_KEY";
const url = "https://app.all-hands.dev/api/v1/app-conversations";
const headers = {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
};
const data = {
initial_message: {
content: [{ type: "text", text: "Check whether there is any incorrect information in the README.md file and send a PR to fix it if so." }]
},
selected_repository: "yourusername/your-repo"
};
async function startConversation() {
try {
const response = await fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(data)
});
const result = await response.json();
// The response contains a start task with the conversation ID
const conversationId = result.app_conversation_id || result.id;
console.log(`Conversation Link: https://app.all-hands.dev/conversations/${conversationId}`);
console.log(`Status: ${result.status}`);
return result;
} catch (error) {
console.error("Error starting conversation:", error);
}
}
startConversation();
Response
The API will return a JSON object with details about the conversation start task:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "WORKING",
"app_conversation_id": "660e8400-e29b-41d4-a716-446655440001",
"sandbox_id": "sandbox-abc123",
"created_at": "2025-01-15T10:30:00Z"
}
The status field indicates the current state of the conversation startup process:
WORKING - Initial processing
WAITING_FOR_SANDBOX - Waiting for sandbox to be ready
PREPARING_REPOSITORY - Cloning and setting up the repository
READY - Conversation is ready to use
ERROR - An error occurred during startup
You may receive an authentication error if:
- You provided an invalid API key.
- You provided the wrong repository name.
- You don’t have access to the repository.
Streaming Conversation Start (Optional)
For real-time updates during conversation startup, you can use the streaming endpoint:
curl -X POST "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": "Your task description here"}]
},
"selected_repository": "yourusername/your-repo"
}'
Streaming Response
The endpoint streams a JSON array incrementally. Each element represents a status update:
[
{"id": "550e8400-e29b-41d4-a716-446655440000", "status": "WORKING", "created_at": "2025-01-15T10:30:00Z"},
{"id": "550e8400-e29b-41d4-a716-446655440000", "status": "WAITING_FOR_SANDBOX", "created_at": "2025-01-15T10:30:00Z"},
{"id": "550e8400-e29b-41d4-a716-446655440000", "status": "PREPARING_REPOSITORY", "created_at": "2025-01-15T10:30:00Z"},
{"id": "550e8400-e29b-41d4-a716-446655440000", "status": "READY", "app_conversation_id": "660e8400-e29b-41d4-a716-446655440001", "sandbox_id": "sandbox-abc123", "created_at": "2025-01-15T10:30:00Z"}
]
Each update is streamed as it occurs, allowing you to provide real-time feedback to users about the conversation startup progress.
Rate Limits
If you have too many conversations running at once, older conversations will be paused to limit the number of concurrent conversations.
If you’re running into issues and need a higher limit for your use case, please contact us at contact@all-hands.dev.
Migrating from V0 to V1 API
The V0 API (/api/conversations) is deprecated and scheduled for removal on April 1, 2026.
Please migrate to the V1 API (/api/v1/app-conversations) as soon as possible.
Key Differences
| Feature | V0 API | V1 API |
|---|
| Endpoint | POST /api/conversations | POST /api/v1/app-conversations |
| Message format | initial_user_msg (string) | initial_message.content (array of content objects) |
| Repository field | repository | selected_repository |
| Response | Immediate conversation_id | Start task with status and eventual app_conversation_id |
Migration Steps
-
Update the endpoint URL: Change from
/api/conversations to /api/v1/app-conversations
-
Update the request body:
- Change
repository to selected_repository
- Change
initial_user_msg (string) to initial_message (object with content array):
// V0 format
{ "initial_user_msg": "Your message here" }
// V1 format
{ "initial_message": { "content": [{"type": "text", "text": "Your message here"}] } }
-
Update response handling: The V1 API returns a start task object. The conversation ID is in the
app_conversation_id field (available when status is READY), or use the id field for the start task ID.
Legacy API (V0) - Deprecated
The V0 API is deprecated since version 1.0.0 and will be removed on April 1, 2026.
New integrations should use the V1 API documented above.
Starting a New Conversation (V0)
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 whether there is any incorrect information in the README.md file and send a PR to fix it if so.",
"repository": "yourusername/your-repo"
}'
import requests
api_key = "YOUR_API_KEY"
url = "https://app.all-hands.dev/api/conversations"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
data = {
"initial_user_msg": "Check whether there is any incorrect information in the README.md file and send a PR to fix it if so.",
"repository": "yourusername/your-repo"
}
response = requests.post(url, headers=headers, json=data)
conversation = response.json()
print(f"Conversation Link: https://app.all-hands.dev/conversations/{conversation['conversation_id']}")
print(f"Status: {conversation['status']}")
const apiKey = "YOUR_API_KEY";
const url = "https://app.all-hands.dev/api/conversations";
const headers = {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
};
const data = {
initial_user_msg: "Check whether there is any incorrect information in the README.md file and send a PR to fix it if so.",
repository: "yourusername/your-repo"
};
async function startConversation() {
try {
const response = await fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(data)
});
const conversation = await response.json();
console.log(`Conversation Link: https://app.all-hands.dev/conversations/${conversation.conversation_id}`);
console.log(`Status: ${conversation.status}`);
return conversation;
} catch (error) {
console.error("Error starting conversation:", error);
}
}
startConversation();
Response (V0)
{
"status": "ok",
"conversation_id": "abc1234"
}