REST API
Cloud Only
The Cloud REST API is available at https://api.adhf.dev. Self-hosted users can access a local API — see Self-hosted API.
This page documents the hosted cloud automation surface.
It does not try to cover:
- local standalone endpoints such as
/api/v1/status - self-hosted runtime operator flows such as session-host recovery
- local terminal mux endpoints such as
/api/v1/mux/*
For those, use the OSS self-hosted docs instead.
Authentication
All API requests require an API key in the Authorization header:
curl -H "Authorization: Bearer adk_..." \
https://api.adhf.dev/api/v1/daemonsCreate API keys from Dashboard → Settings → API Keys. Each key can be scoped to specific permissions.
For normal cloud automation, API keys are the main auth surface.
Some sensitive cloud-account mutations now require a recent browser login instead of API-key auth. Those routes expect a fresh dashboard JWT session and return 403 RECENT_LOGIN_REQUIRED when called with an API key or a stale session.
Current recent-login protected routes:
POST /api/v1/webhooksPATCH /api/v1/webhooks/{webhookId}DELETE /api/v1/webhooks/{webhookId}POST /api/v1/webhooks/{webhookId}/testPOST /api/v1/daemons/{daemonId}/disconnectPOST /api/v1/daemons/{daemonId}/revoke
Scopes
| Scope | Description |
|---|---|
ide:read | List daemons, read IDE state |
ide:control | Launch/stop IDEs, send daemon commands |
agent:read | Read chat messages, agent status |
agent:control | Send messages, approve/reject actions |
terminal:exec | Execute terminal commands on machines |
webhook:manage | Inspect deliveries and, with a recent dashboard login, manage webhooks |
Public API Shape
For most cloud integrations, think in these layers:
GET /api/v1/daemonsto find connected machinesGET /api/v1/daemons/{daemonId}/statusto inspect machine and session state/api/v1/shortcuts/*for the common agent actions you actually want/api/v1/webhooks/*for event delivery to your own systems
Prefer Shortcuts unless you specifically need the raw daemon command router.
All daemon and shortcut routes are scoped to machines and sessions owned by the authenticated cloud account. Supplying some other account's daemon or synthetic session id returns 404 instead of crossing account boundaries.
Daemons
Manage connected machines (daemons) and their IDEs.
List Daemons
GET /api/v1/daemonsScope: ide:read
Returns all connected machines with their managed IDEs, CLIs, and ACP agents.
Response:
{
"daemons": [
{
"id": "c79baa8f...",
"hostname": "M1-Server",
"nickname": "작업용",
"platform": "darwin",
"cdpConnected": true,
"ides": [
{ "id": "c79baa8f:ide:cursor_myproject", "type": "cursor", "cdpConnected": true }
],
"clis": [
{ "id": "c79baa8f:cli:gemini-cli", "type": "gemini-cli", "name": "Gemini CLI" }
],
"acps": [
{ "id": "c79baa8f:acp:claude-acp", "type": "claude-acp" }
]
}
]
}Get Daemon Status
GET /api/v1/daemons/{daemonId}/statusScope: ide:read
Returns detailed daemon status including IDE/CLI state, workspace info, and agent activity.
Send Daemon Command
POST /api/v1/daemons/{daemonId}/commandScope: ide:control
Send a direct command to the target machine.
For most integrations, prefer the Shortcuts API below. POST /daemons/:id/command is the lower-level escape hatch.
Body:
{
"type": "send_chat",
"payload": { "message": "Hello!" }
}Available Command Types
| Command | Target | Payload | Description |
|---|---|---|---|
send_chat | IDE/CLI | message | Send a chat message |
read_chat | IDE/CLI | — | Read current chat contents |
resolve_action | IDE/CLI | action | Approve/reject agent action |
screenshot | IDE | width? | Take a screenshot |
launch_ide | Daemon | ideType, enableCdp? | Launch an IDE |
launch_cli | Daemon | cliType, dir?, model? | Start CLI/ACP session |
stop_cli | Daemon | cliType | Stop CLI session |
Not every command in the internal router belongs in public automation material. If you are building a normal integration, stay on the documented command set or the shortcut endpoints.
Execute Terminal Command
POST /api/v1/daemons/{daemonId}/terminalScope: terminal:exec
Execute a terminal command on the daemon machine.
Body:
{
"command": "ls -la",
"name": "my-terminal",
"cwd": "/home/user"
}Disconnect Daemon
POST /api/v1/daemons/{daemonId}/disconnectScope: ide:control
Force disconnect the daemon. The daemon can reconnect automatically.
This is a recent-login protected cloud action. API keys and stale browser sessions receive 403 RECENT_LOGIN_REQUIRED.
Revoke Daemon Token
POST /api/v1/daemons/{daemonId}/revokeScope: ide:control
Revoke the daemon's connection token permanently. Requires running adhdev setup again on the machine.
This is a recent-login protected cloud action. API keys and stale browser sessions receive 403 RECENT_LOGIN_REQUIRED.
Shortcuts
Convenience endpoints for the most common agent actions.
Launch IDE / CLI / ACP
POST /api/v1/shortcuts/{daemonId}/launchScope: ide:control
Body:
{ "type": "cursor" }{ "type": "gemini-cli", "dir": "/path/to/project" }{ "type": "claude-acp", "dir": "/path", "model": "opus" }Stop CLI / ACP
POST /api/v1/shortcuts/{daemonId}/stopScope: ide:control
Body:
{ "type": "gemini-cli" }Send Chat Message
POST /api/v1/shortcuts/{ideId}/chatScope: agent:control
Send a message to an AI agent. The ideId is the machine-scoped target ID returned by the daemon/session status APIs, including synthetic session routes like {daemonId}:session:{sessionId}.
This is the default send path for external automation.
Body (legacy text form):
{ "message": "Fix the bug in auth.ts" }Body (canonical envelope form):
{
"input": {
"parts": [
{ "type": "text", "text": "Fix the bug in auth.ts" }
],
"textFallback": "Fix the bug in auth.ts"
}
}Optional — specify agent type for multi-agent IDEs:
{ "message": "Fix the bug", "agentType": "cursor" }You must provide either message or input.
Read Chat
GET /api/v1/shortcuts/{ideId}/chatScope: agent:read
Read the current chat contents from an agent. Optionally filter by ?agentType=cursor.
Chat Debug Bundle
GET /api/v1/shortcuts/{ideId}/chat/debug
POST /api/v1/shortcuts/{ideId}/chat/debugScope: agent:read
Build a bounded, sanitized debug bundle for the current chat/session. The daemon generates the authoritative provider/parser/session/terminal evidence; POST may include a dashboard frontendSnapshot to supplement it with currently rendered frontend state.
Optional body for POST:
{ "agentType": "hermes", "frontendSnapshot": { "activeConversation": { "sessionId": "session_..." } } }The response includes bundle and copy-ready text. Secrets and credentials are redacted by default.
Approve / Reject Action
POST /api/v1/shortcuts/{ideId}/approveScope: agent:control
Approve or reject a pending agent action.
Body:
{ "action": "approve" }or
{ "action": "reject", "agentType": "cursor" }Get Agent Status
GET /api/v1/shortcuts/{ideId}/statusScope: agent:read
Returns current status (idle, generating, waiting_approval, error), provider summary metadata/controls when present, and workspace info.
Collaboration APIs
Collaboration features have their own API surface under /api/v1/orgs/*.
That includes:
- creating or listing Rafts and Team Workspaces
- inviting members
- reading collaboration machine/session state
- requesting or approving shared-session access
Invite acceptance is bound to the invited email address. If the signed-in cloud user does not match the invited email, the join request is rejected.
If you are not using collaboration features, you can ignore this part of the API entirely.
Webhooks
Manage webhook subscriptions for real-time event notifications. See Webhooks feature guide for setup instructions and signature verification.
List Webhooks
GET /api/v1/webhooksScope: webhook:manage
Create Webhook
POST /api/v1/webhooksScope: webhook:manage
Body:
{
"url": "https://example.com/hook",
"events": ["agent:generating_completed", "agent:waiting_approval"]
}Use ["*"] to subscribe to all events. The response includes a secret (shown only once) for signature verification.
This is a recent-login protected cloud action. API keys and stale browser sessions receive 403 RECENT_LOGIN_REQUIRED.
Toggle Webhook
PATCH /api/v1/webhooks/{webhookId}Scope: webhook:manage
Body:
{ "active": false }This is a recent-login protected cloud action. API keys and stale browser sessions receive 403 RECENT_LOGIN_REQUIRED.
Delete Webhook
DELETE /api/v1/webhooks/{webhookId}Scope: webhook:manage
This is a recent-login protected cloud action. API keys and stale browser sessions receive 403 RECENT_LOGIN_REQUIRED.
List Deliveries
GET /api/v1/webhooks/{webhookId}/deliveries?limit=20Scope: webhook:manage
Returns recent delivery history with status codes, response bodies, and timing.
Test Webhook
POST /api/v1/webhooks/{webhookId}/testScope: webhook:manage
Sends a test webhook:test event to the webhook URL.
This is a recent-login protected cloud action. API keys and stale browser sessions receive 403 RECENT_LOGIN_REQUIRED.
Events
These events are delivered to webhooks and also drive live cloud notification flows.
| Event | Description |
|---|---|
agent:generating_started | Agent started generating a response |
agent:generating_completed | Agent finished generating (includes duration in seconds) |
agent:waiting_approval | Agent is waiting for user approval |
agent:error | Agent encountered an error |
machine:connected | Machine came online |
machine:disconnected | Machine went offline |
Event Payload
{
"event": "agent:generating_completed",
"ideId": "c79baa8f:ide:cursor_myproject",
"ideType": "cursor",
"duration": 12.5,
"timestamp": 1710000000000
}Typical Flow
The most common API flow is:
- List machines with
GET /api/v1/daemons - Pick a target agent from the daemon status payload
- Send a message with
POST /api/v1/shortcuts/{ideId}/chat - Poll
GET /api/v1/shortcuts/{ideId}/statusor use webhooks - Read the transcript with
GET /api/v1/shortcuts/{ideId}/chat
What This Page Excludes
If you are looking for any of these, this is the wrong API page:
- standalone
GET /api/v1/status - standalone
POST /api/v1/command - runtime snapshot/events endpoints for hosted local CLI sessions
- terminal mux workspace endpoints
Those belong to Self-hosted API.
Rate Limits
Per-Request Limits
| Limit | Value |
|---|---|
| API Key | 120 requests / minute |
| IP address | 60 requests / minute |
| Auth endpoints | 10 requests / 5 minutes |
| Command timeout | 60 seconds |
Monthly Call Limits
| Plan | Monthly API Calls |
|---|---|
| Free | 1,000 |
| Pro | 50,000 |
| Team | 500,000 |
| Enterprise | Unlimited |
Error Codes
| Status | Code | Description |
|---|---|---|
400 | — | Bad request (validation failed) |
401 | AUTH_REQUIRED | Missing Authorization header |
401 | AUTH_INVALID | Invalid or expired API key |
403 | AUTH_FORBIDDEN | API key lacks required scope |
403 | RECENT_LOGIN_REQUIRED | Sensitive cloud action requires a fresh dashboard login instead of API-key auth or a stale session |
404 | — | Daemon/resource not found, expired invite/share, or target not owned by the authenticated account |
429 | RATE_LIMITED | Per-minute rate limit exceeded |
429 | API_LIMIT_EXCEEDED | Monthly API call limit reached |
500 | — | Command send failed (daemon offline) |
503 | — | Daemon connected but WebSocket disconnected |
504 | — | Command response timeout (exceeded 60s) |
