API Documentation

Programmatically create, manage, and interact with coding agents from your application.

Getting Started

1. Create an account and sign in to your dashboard.

2. In the API Tokens section, click Create Token and give it a label (e.g., "production").

3. Copy the token immediately — it's only shown once. Store it securely in your server environment variables.

Authentication

All API requests are authenticated using a Bearer token in the Authorization header.

Authorization: Bearer ha_live_your_token_here

Tokens are scoped to your organization. Any agent created via the API will appear in your dashboard.

API Reference

POST/api/v1/agents

Create a new coding agent with an optional initial prompt. The endpoint provisions a Docker container, waits for it to be ready (up to 60s), and returns the agent URL and any sessions created.

Request Headers

AuthorizationBearer ha_live_... (required)
Content-Typeapplication/json

Request Body

FieldTypeDescription
namestringAgent name (1-100 characters). Required.
initialPromptstringInstructions sent to the agent on startup as a visible user message. Optional.
hiddenPromptstringSystem-level instructions injected as a hidden context file. Not visible to the user in the chat UI. Optional.
scopeIdstringAssign the agent to a scope by ID. The agent will only receive secrets from this scope. Optional.
scopestringAssign the agent to a scope by name (alternative to scopeId). Optional.
modelstringOverride the default model for this agent. If omitted, the org default is used. Available models:
  • opencode/nemotron-3-super-free — Nemotron 3 Super
  • opencode/minimax-m2.5-free — MiniMax M2.5
  • opencode/big-pickle — Big Pickle
  • opencode/mimo-v2-flash-free — Mimo V2 Flash
  • anthropic/claude-opus-4-6 — Claude Opus 4.6
  • anthropic/claude-sonnet-4-6 — Claude Sonnet 4.6

Response (200)

{
  "agentId": "clx1abc2def3...",
  "scopeId": "clx9scope1...",
  "url": "https://a10042.hostedagents.ai",
  "sessions": [
    {
      "id": "ses_abc123...",
      "title": null,
      "url": "https://a10042.hostedagents.ai/Lw/session/ses_abc123..."
    }
  ]
}
agentIdUnique agent identifier.
urlBase URL of the agent's coding environment.
sessionsArray of sessions. Contains one session if initialPrompt was provided, otherwise empty. Each session has id, title, and url.

Error Responses

StatusMeaning
401Invalid or missing API token.
400Invalid request body or missing name.
429Agent limit reached for your plan.
503No available ports. Retry later.
504Agent provisioning timed out.
GET/api/v1/agents/:agentId

Get the current status of an agent, including whether it's busy processing a task, its live sessions, and any error information.

Path Parameters

agentIdThe agent ID returned from POST /api/v1/agents.

Response (200)

{
  "agentId": "clx1abc2def3...",
  "name": "my-agent",
  "status": "RUNNING",
  "busy": true,
  "url": "https://a10042.hostedagents.ai",
  "sessions": [
    {
      "id": "ses_abc123...",
      "title": "Build REST API",
      "url": "https://a10042.hostedagents.ai/Lw/session/ses_abc123..."
    }
  ],
  "errorMsg": null,
  "createdAt": "2025-01-15T10:30:00.000Z"
}
statusAgent state: PROVISIONING, RUNNING, STOPPED, or ERROR.
busytrue if the agent is currently processing a task, false if idle. Useful for polling.
sessionsLive sessions fetched from the running agent. Each agent can have multiple sessions (chat threads).
errorMsgError details if status is ERROR, otherwise null.

Error Responses

401Invalid or missing API token.
404Agent not found or does not belong to your organization.
GET/api/v1/agents/:agentId/messages

Retrieve message history from an agent. Fetch messages from a specific session, or omit the session ID to get messages from all sessions.

Parameters

ParamInDescription
agentIdpathAgent ID. Required.
sessionIdquerySpecific session ID. Optional — if omitted, returns messages from all sessions.

Response — with sessionId (200)

{
  "sessionId": "ses_abc123...",
  "messages": [
    {
      "id": "msg_001",
      "info": {
        "role": "user",
        "parts": [{ "type": "text", "text": "Build a REST API" }]
      }
    },
    {
      "id": "msg_002",
      "info": {
        "role": "assistant",
        "parts": [{ "type": "text", "text": "I'll create a REST API..." }],
        "time": { "created": 1705312200, "completed": 1705312260 },
        "cost": 0.08182125,
        "tokens": {
          "total": 12801, "input": 3, "output": 97, "reasoning": 0,
          "cache": { "read": 0, "write": 12701 }
        }
      }
    }
  ],
  "usage": {
    "cost": 0.08182125,
    "tokens": {
      "total": 12801, "input": 3, "output": 97, "reasoning": 0,
      "cache": { "read": 0, "write": 12701 }
    }
  }
}

Response — without sessionId (200)

{
  "sessions": [
    {
      "sessionId": "ses_abc123...",
      "title": "Build REST API",
      "messages": [ ... ],
      "usage": { "cost": 1.3029, "tokens": { "total": 891149, ... } }
    },
    {
      "sessionId": "ses_def456...",
      "title": "Fix auth bug",
      "messages": [ ... ],
      "usage": { "cost": 0.0523, "tokens": { "total": 34201, ... } }
    }
  ]
}

Error Responses

401Invalid or missing API token.
400Agent is not running.
404Agent or session not found.
502Agent is not responding.
POST/api/v1/agents/:agentId/messages

Send a message to an agent. If no sessionId is provided, a new session is created automatically. The message is sent asynchronously — the endpoint returns immediately and the agent begins processing in the background.

Request Body

FieldTypeDescription
messagestringThe message to send. Required.
sessionIdstringTarget session ID. Optional — if omitted, a new session is created.

Response (200)

{
  "sessionId": "ses_abc123...",
  "sent": true
}
sessionIdThe session the message was sent to (useful when a new session was auto-created).
sentAlways true on success.

Error Responses

401Invalid or missing API token.
400Invalid JSON body, missing message, or agent is not running.
404Agent not found.
502Agent is not responding or failed to create session / send message.
POST/api/v1/agents/:agentId/start

Start a STOPPED agent. The endpoint restarts the agent's container and waits up to 30s for it to become healthy before returning. If the agent is already RUNNING, the call succeeds with started: false.

Path Parameters

agentIdThe agent ID. Required.

Response (200)

{ "agentId": "clx1abc2def3...", "status": "RUNNING", "started": true }
startedtrue if the container was started, false if it was already running.

Error Responses

401Invalid or missing API token.
400Agent is not in a startable state (e.g. PROVISIONING or ERROR).
404Agent not found.
503Container failed to start, or concurrent agent cap reached.
POST/api/v1/agents/:agentId/stop

Stop a RUNNING agent. The container is gracefully stopped (3s timeout) and the agent's status is set to STOPPED. The agent's sessions and history are preserved and it can be restarted later.

Path Parameters

agentIdThe agent ID. Required.

Response (200)

{ "agentId": "clx1abc2def3...", "status": "STOPPED", "stopped": true }
stoppedtrue if the container was stopped, false if it was already stopped.

Error Responses

401Invalid or missing API token.
400Agent is not in a stoppable state (e.g. PROVISIONING or ERROR).
404Agent not found.
503Container failed to stop.
POST/api/v1/agents/:agentId/restart

Restart an agent. If the agent is RUNNING, it is stopped first, then started again. If already STOPPED, it is started directly. Waits up to 30s for the container to become healthy before returning.

Path Parameters

agentIdThe agent ID. Required.

Response (200)

{ "agentId": "clx1abc2def3...", "status": "RUNNING", "restarted": true }

Error Responses

401Invalid or missing API token.
400Agent cannot be restarted from its current state (e.g. PROVISIONING or ERROR).
404Agent not found.
503Container failed to stop or start, or concurrent agent cap reached.
GET/api/v1/agents/:agentId/usage

Get token usage and cost for an agent, broken down by session. Aggregates the cost and tokens fields from every assistant message across all sessions.

Path Parameters

agentIdThe agent ID. Required.

Response (200)

{
  "agentId": "clx1abc2def3...",
  "totalCost": 1.3029,
  "totalTokens": {
    "total": 891149,
    "input": 4,
    "output": 233,
    "reasoning": 0,
    "cache": { "read": 853210, "write": 37702 }
  },
  "sessions": [
    {
      "sessionId": "ses_abc123...",
      "title": "Build REST API",
      "cost": 1.1712,
      "tokens": {
        "total": 753895,
        "input": 3,
        "output": 197,
        "reasoning": 0,
        "cache": { "read": 720100, "write": 33595 }
      }
    },
    {
      "sessionId": "ses_def456...",
      "title": "Fix auth bug",
      "cost": 0.1317,
      "tokens": {
        "total": 137254,
        "input": 1,
        "output": 36,
        "reasoning": 0,
        "cache": { "read": 133110, "write": 4107 }
      }
    }
  ]
}

Response Fields

FieldDescription
totalCostTotal estimated cost in USD across all sessions.
totalTokensAggregated token counts across all sessions.
totalTokens.totalTotal tokens (input + output + cache read/write).
totalTokens.inputNon-cached input tokens.
totalTokens.outputOutput tokens generated by the model.
totalTokens.reasoningExtended-thinking tokens (model-dependent).
totalTokens.cache.readTokens served from prompt cache (lower cost).
totalTokens.cache.writeTokens written to prompt cache.
sessionsPer-session breakdown with the same cost/tokens structure.

Error Responses

401Invalid or missing API token.
400Agent is not running.
404Agent not found.
502Agent is not responding.
POST/api/v1/agents/:agentId/abort

Cancel an in-progress generation — the equivalent of pressing Esc in the OpenCode TUI. The agent stays running and can receive new messages immediately. To stop the agent container entirely, use the stop endpoint instead.

Path Parameters

agentIdThe agent ID. Required.

Request Body (optional)

FieldTypeDescription
sessionIdstringAbort a specific session. If omitted, aborts all sessions on the agent.
// Abort a specific session
{ "sessionId": "ses_abc123..." }

// Abort all sessions (empty body or omit entirely)
{}

Response (200)

// With sessionId
{ "agentId": "clx1abc2def3...", "sessionId": "ses_abc123...", "aborted": true }

// Without sessionId — aborts all sessions
{ "agentId": "clx1abc2def3...", "aborted": ["ses_abc123...", "ses_def456..."] }

Error Responses

401Invalid or missing API token.
400Agent is not running.
404Agent not found.
502Agent is not responding.
POST/api/v1/agents/:agentId/files

Upload a file into the agent's filesystem at /workspace/uploads/. The agent can read and reference uploaded files in subsequent messages. Accepts multipart/form-data.

Path Parameters

agentIdThe agent ID. Required.

Request Body (multipart/form-data)

FieldTypeDescription
fileFileThe file to upload. Max 50MB per file, 100MB total per agent.

Allowed file types

Documents & data: .txt .md .pdf .csv .json .xml .yaml .yml .toml

Code & config: .py .js .ts .jsx .tsx .html .css .scss .sql .rs .go .java .c .cpp .h .rb .php .swift .kt

Images: .png .jpg .jpeg .gif .webp

const form = new FormData();
form.append("file", fileBlob, "data.csv");

const res = await fetch("https://hostedagents.ai/api/v1/agents/{agentId}/files", {
  method: "POST",
  headers: { "Authorization": `Bearer ${TOKEN}` },
  body: form,
});

Response (200)

{
  "path": "/workspace/uploads/data.csv",
  "name": "data.csv",
  "size": 204800
}

Error Responses

401Invalid or missing API token.
400Missing file, disallowed file type, file exceeds 50MB, or agent total exceeds 100MB.
404Agent not found.
502Failed to write file to agent container.

Permissions & Questions

Agents may pause and wait for human input in two ways: a permission request (the agent wants to perform an action and needs approval) or a question (the agent needs structured input before it can continue). Poll these endpoints while the agent is busy and respond when requests are pending.

GET/api/v1/agents/:agentId/permissions

Returns all pending permission requests for the agent. A permission request is created when the agent wants to run a tool (e.g. execute a shell command) that requires explicit approval. The agent is paused until a reply is submitted.

Response (200)

{
  "permissions": [
    {
      "id": "perm_abc123",
      "sessionID": "sess_xyz789",
      "permission": "bash",
      "patterns": ["rm -rf /tmp/build"],
      "metadata": {},
      "always": false,
      "tool": {
        "messageID": "msg_def456",
        "callID": "call_ghi012"
      }
    }
  ]
}
FieldDescription
idUnique permission request ID. Pass this to the reply endpoint.
permissionThe type of permission being requested (e.g. bash, write, webfetch).
patternsThe specific commands or paths the agent wants to act on.
alwaysWhether this is a request to always allow this pattern in future.

Errors

400Agent is not running.
404Agent not found.
502Agent container is not responding.
POST/api/v1/agents/:agentId/permissions/:permissionId/reply

Reply to a pending permission request. The agent resumes immediately after a reply is submitted.

Request Body

{
  "reply": "once",      // "once" | "always" | "reject"
  "message": "..."      // optional — rejection reason shown to the agent
}
FieldTypeDescription
replystring requiredonce — allow this one time.
always — allow and remember for future requests matching this pattern.
reject — deny the action.
messagestringOptional message to pass back to the agent (useful when rejecting to explain why).

Response (200)

{ "replied": true, "reply": "once" }

Errors

400Agent is not running, or reply is not one of the accepted values.
404Agent not found.
502Agent container is not responding.
GET/api/v1/agents/:agentId/questions

Returns pending questions the agent is waiting for the user to answer. Questions are structured multiple-choice prompts. The agent is paused until a reply is submitted.

Response (200)

{
  "questions": [
    {
      "id": "q_abc123",
      "questions": [
        {
          "question": "How would you like me to implement this?",
          "header": "Approach",
          "options": [
            { "label": "Simple", "description": "Quick, minimal implementation" },
            { "label": "Full", "description": "Complete with tests and error handling" }
          ],
          "multiSelect": false
        }
      ]
    }
  ]
}
FieldDescription
idUnique question ID. Pass this to the reply endpoint.
questions[].questionThe question text shown to the user.
questions[].optionsAvailable answer choices, each with a label and description.
questions[].multiSelectIf true, multiple options can be selected in the reply.

Errors

400Agent is not running.
404Agent not found.
502Agent container is not responding.
POST/api/v1/agents/:agentId/questions/:questionId/reply

Submit answers to a pending question. The answers field is an array of arrays — one inner array per question in the questions array, containing the selected option label(s). The agent resumes immediately after a reply is submitted.

Request Body

{
  "answers": [
    ["Simple"]   // one inner array per question; include multiple labels for multiSelect
  ]
}

Each inner array corresponds to the question at the same index in questions[]. For single-select questions provide one label. For multiSelect questions provide multiple labels in the inner array.

Response (200)

{ "replied": true }

Errors

400Agent is not running, or answers is missing or not an array.
404Agent not found.
502Agent container is not responding or question ID is invalid.

Scopes

Scopes let you group agents and secrets together. Agents in a scope only receive the secrets belonging to that scope. Agents and secrets without a scope operate at the organization level.

GET/api/v1/scopes

List all scopes in your organization.

Response (200)

{
  "scopes": [
    {
      "id": "clx9scope1...",
      "name": "production",
      "description": "Production environment",
      "agentCount": 3,
      "secretCount": 2,
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    }
  ]
}
POST/api/v1/scopes

Create a new scope.

Request Body

FieldTypeDescription
namestringScope name (1-100 characters). Required. Must be unique within the organization.
descriptionstringDescription of the scope. Optional.

Response (201)

{
  "id": "clx9scope1...",
  "name": "production",
  "description": "Production environment",
  "createdAt": "2025-01-01T00:00:00.000Z"
}

Error Responses

400Invalid request body or missing name.
401Invalid or missing API token.
409A scope with this name already exists.
GET/api/v1/scopes/:scopeId

Get details for a scope, including its agents and secrets.

Path Parameters

scopeIdThe scope ID. Required.

Response (200)

{
  "id": "clx9scope1...",
  "name": "production",
  "description": "Production environment",
  "createdAt": "2025-01-01T00:00:00.000Z",
  "updatedAt": "2025-01-01T00:00:00.000Z",
  "agents": [
    { "id": "clx1abc...", "name": "my-agent", "status": "RUNNING", "createdAt": "..." }
  ],
  "secrets": [
    { "id": "clx2def...", "key": "ANTHROPIC_API_KEY", "createdAt": "...", "updatedAt": "..." }
  ]
}
PATCH/api/v1/scopes/:scopeId

Update a scope's name or description.

Request Body

FieldTypeDescription
namestringNew scope name (1-100 characters). Optional.
descriptionstringNew description. Optional.

Response (200)

{
  "id": "clx9scope1...",
  "name": "staging",
  "description": "Updated description",
  "updatedAt": "2025-01-02T00:00:00.000Z"
}

Error Responses

400Invalid body or no fields to update.
404Scope not found.
409A scope with this name already exists.
DELETE/api/v1/scopes/:scopeId

Delete a scope. Agents and secrets in the scope will become org-level (unscoped). Running containers are not affected.

Path Parameters

scopeIdThe scope ID. Required.

Response (200)

{ "deleted": true }

Secrets

Secrets are encrypted environment variables injected into agent containers at startup. Org-level secrets are injected into unscoped agents. Scoped secrets are injected only into agents in that scope.

GET/api/v1/secrets

List org-level secrets (keys only, values are never returned).

Response (200)

{
  "secrets": [
    {
      "id": "clx2def...",
      "key": "ANTHROPIC_API_KEY",
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    }
  ]
}
PUT/api/v1/secrets

Create or update an org-level secret. If the key already exists, its value is replaced.

Request Body

FieldTypeDescription
keystringUppercase letters, digits, and underscores (e.g. MY_API_KEY). Required.
valuestringThe secret value. Required. Stored encrypted.

Response (201 created / 200 updated)

{ "id": "clx2def...", "key": "ANTHROPIC_API_KEY", "created": true }
DELETE/api/v1/secrets/:key

Delete an org-level secret by key name. Already-running agents are not affected.

Path Parameters

keyThe secret key (e.g. ANTHROPIC_API_KEY). Required.

Response (200)

{ "deleted": true }
GET/api/v1/scopes/:scopeId/secrets

List secrets in a scope (keys only).

Path Parameters

scopeIdThe scope ID. Required.

Response (200)

{
  "secrets": [
    { "id": "clx2def...", "key": "ANTHROPIC_API_KEY", "createdAt": "...", "updatedAt": "..." }
  ]
}
PUT/api/v1/scopes/:scopeId/secrets

Create or update a secret in a scope. If the key already exists in this scope, its value is replaced.

Request Body

FieldTypeDescription
keystringUppercase letters, digits, and underscores. Required.
valuestringThe secret value. Required.

Response (201 created / 200 updated)

{ "id": "clx2def...", "key": "ANTHROPIC_API_KEY", "created": true }
DELETE/api/v1/scopes/:scopeId/secrets/:key

Delete a secret from a scope by key name.

Path Parameters

scopeIdThe scope ID. Required.
keyThe secret key. Required.

Response (200)

{ "deleted": true }

Quick Start with cURL

Create an Agent

curl -X POST https://hostedagents.ai/api/v1/agents \
  -H "Authorization: Bearer ha_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-agent",
    "initialPrompt": "Build a REST API for user management",
    "model": "opencode/nemotron-3-super-free"
  }'

# Response:
# {
#   "agentId": "clx1abc2def3...",
#   "sessions": [{ "id": "ses_abc123...", "title": null, "messageId": "msg_..." }]
# }

Check Agent Status

curl https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID \
  -H "Authorization: Bearer ha_live_your_token_here"

# Response includes: status, busy, sessions[], url

Send a Message

curl -X POST https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/messages \
  -H "Authorization: Bearer ha_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "ses_abc123...",
    "message": "Add authentication middleware"
  }'

# Response: { "sessionId": "ses_abc123...", "sent": true }

Get Message History

# Get messages from a specific session
curl "https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/messages?sessionId=ses_abc123" \
  -H "Authorization: Bearer ha_live_your_token_here"

# Get messages from ALL sessions
curl https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/messages \
  -H "Authorization: Bearer ha_live_your_token_here"

Start a Stopped Agent

curl -X POST https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/start \
  -H "Authorization: Bearer ha_live_your_token_here"

# Response: { "agentId": "...", "status": "RUNNING", "started": true }

Stop an Agent

curl -X POST https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/stop \
  -H "Authorization: Bearer ha_live_your_token_here"

# Response: { "agentId": "...", "status": "STOPPED", "stopped": true }

Restart an Agent

curl -X POST https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/restart \
  -H "Authorization: Bearer ha_live_your_token_here"

# Response: { "agentId": "...", "status": "RUNNING", "restarted": true }

Handle a Permission Request

# 1. Poll for pending permissions
curl https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/permissions \
  -H "Authorization: Bearer ha_live_your_token_here"

# Response:
# {
#   "permissions": [{
#     "id": "perm_abc123",
#     "permission": "bash",
#     "patterns": ["rm -rf /tmp/build"],
#     "always": false
#   }]
# }

# 2. Approve it once
curl -X POST https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/permissions/perm_abc123/reply \
  -H "Authorization: Bearer ha_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "reply": "once" }'

# Response: { "replied": true, "reply": "once" }

Answer a Question

# 1. Poll for pending questions
curl https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/questions \
  -H "Authorization: Bearer ha_live_your_token_here"

# Response:
# {
#   "questions": [{
#     "id": "q_abc123",
#     "questions": [{
#       "question": "How would you like me to implement this?",
#       "options": [
#         { "label": "Simple", "description": "Quick, minimal implementation" },
#         { "label": "Full",   "description": "Complete with tests" }
#       ]
#     }]
#   }]
# }

# 2. Submit your answer
curl -X POST https://hostedagents.ai/api/v1/agents/YOUR_AGENT_ID/questions/q_abc123/reply \
  -H "Authorization: Bearer ha_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "answers": [["Simple"]] }'

# Response: { "replied": true }

Create a Scope

curl -X POST https://hostedagents.ai/api/v1/scopes \
  -H "Authorization: Bearer ha_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "name": "production", "description": "Production environment" }'

# Response: { "id": "clx9scope1...", "name": "production", ... }

Add a Secret to a Scope

curl -X PUT https://hostedagents.ai/api/v1/scopes/YOUR_SCOPE_ID/secrets \
  -H "Authorization: Bearer ha_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "key": "ANTHROPIC_API_KEY", "value": "sk-ant-..." }'

# Response: { "id": "clx2def...", "key": "ANTHROPIC_API_KEY", "created": true }

Create an Agent in a Scope

curl -X POST https://hostedagents.ai/api/v1/agents \
  -H "Authorization: Bearer ha_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod-agent",
    "scope": "production",
    "initialPrompt": "Build a REST API"
  }'

# The agent receives only secrets from the "production" scope

Polling for Completion

After sending a message, the agent processes it asynchronously. Use the busy field from the agent status endpoint to poll until the task is complete:

async function waitForAgent(agentId: string, token: string) {
  const headers = { Authorization: `Bearer ${token}` };
  const base = "https://hostedagents.ai/api/v1/agents";

  while (true) {
    const res = await fetch(`${base}/${agentId}`, { headers });
    const data = await res.json();

    if (!data.busy) {
      // Agent is idle — task is complete
      return data;
    }

    // Wait 2 seconds before checking again
    await new Promise((r) => setTimeout(r, 2000));
  }
}

Embedding in Your App

The agent's coding environment runs in a standard web page and can be embedded directly in an iframe. No authentication is required to access the agent once it's running.

Server-side: Create the Agent

Call the API from your backend to create an agent and get the session URL:

// Node.js / TypeScript example
const response = await fetch("https://hostedagents.ai/api/v1/agents", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.HOSTEDAGENTS_API_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "project-agent",
    initialPrompt: "Your instructions here...",
  }),
});

const { agentId, url, sessions } = await response.json();
const sessionUrl = sessions[0]?.url;
// sessionUrl = "https://a10042.hostedagents.ai/Lw/session/ses_abc123"

Client-side: Embed the Agent

Render the session URL in an iframe. The coding environment will load with the initial prompt already running:

<iframe
  src="https://a10042.hostedagents.ai/Lw/session/ses_abc123"
  style="width: 100%; height: 700px; border: 1px solid #e0e0e0;"
  allow="clipboard-read; clipboard-write"
></iframe>

Full Integration Example

A complete example showing how to create an agent, send follow-up messages, poll for completion, and embed the environment:

const API = "https://hostedagents.ai/api/v1";
const TOKEN = process.env.HOSTEDAGENTS_API_TOKEN;
const headers = {
  Authorization: `Bearer ${TOKEN}`,
  "Content-Type": "application/json",
};

// 1. Create an agent
const createRes = await fetch(`${API}/agents`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    name: "build-agent",
    initialPrompt: "Set up a Node.js Express project with TypeScript",
  }),
});
const { agentId, sessions } = await createRes.json();
const sessionId = sessions[0]?.id;

// 2. Wait for the initial prompt to finish
async function waitUntilIdle() {
  while (true) {
    const res = await fetch(`${API}/agents/${agentId}`, {
      headers: { Authorization: `Bearer ${TOKEN}` },
    });
    const data = await res.json();
    if (!data.busy) return data;
    await new Promise((r) => setTimeout(r, 2000));
  }
}
await waitUntilIdle();

// 3. Send a follow-up message to the same session
await fetch(`${API}/agents/${agentId}/messages`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    sessionId,
    message: "Now add user authentication with JWT",
  }),
});
await waitUntilIdle();

// 4. Retrieve the full conversation
const msgRes = await fetch(
  `${API}/agents/${agentId}/messages?sessionId=${sessionId}`,
  { headers: { Authorization: `Bearer ${TOKEN}` } }
);
const { messages } = await msgRes.json();
console.log(`Total messages: ${messages.length}`);

Keep your API token on your server. Never expose it to the client. The session URL is safe to pass to the browser — it only grants access to that specific agent session.

Questions? contact@hostedagents.ai