Agent API
Use this when: you want to embed long-lived agents inside your own product — create agents, start sessions, send messages, and stream responses back to your users.
Don't use this when: you only want to call an LLM with one key (use the API Gateway instead — no sessions, no agents, same key). Or if you want to use agents from an MCP client (see MCP server).
Everything lives under https://api.agentsky.dev/v1. Authenticate with Authorization: Bearer ast_… (an API key from Developer → API keys or sky auth login). Management is request/response; conversation is a 202-send plus one standing SSE stream.
The model in 30 seconds
Agent ← reusable spec (harness, instructions, capabilities)
└─ Session ← one conversation thread; holds context and history
└─ Events ← messages in, responses out, as a streamAn agent is what you configure once. A session is what runs. Your application sends user.message events and reads the stream until session.status_idle — the same loop every time.
Basic: end to end in three API calls
1. Create an agent
curl -X POST https://api.agentsky.dev/v1/agents \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{
"displayName": "Research Agent",
"agentType": "hermes",
"llm": "claude-sonnet-5"
}'
# → { "id": "agent_…", "defaultSessionId": "sess_…", … }2. Start a session and send the first message
curl -X POST https://api.agentsky.dev/v1/sessions \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{
"agent": "agent_…",
"initial_events": [
{ "type": "user.message",
"content": [{ "type": "text", "text": "Summarize the signups from today" }] }
]
}'
# → { "id": "sess_…", "status": "running", … }3. Stream the response
curl -N https://api.agentsky.dev/v1/sessions/sess_.../stream \
-H "Authorization: Bearer ast_..."
# SSE frames until session.status_idle
# id: msg-77e0c4…
# event: agent.message
# data: {"id":"msg-…","type":"agent.message","text":"Signups today: 42…"}
# …
# event: session.status_idle
# data: {"stop_reason":{"type":"end_turn"}}Read the stream until you see session.status_idle. The stream stays open — subsequent turns post another event and wait again.
Continue the conversation
curl -X POST https://api.agentsky.dev/v1/sessions/sess_.../events \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{
"requireIdle": true,
"events": [
{ "type": "user.message",
"content": [{ "type": "text", "text": "Which cohort drove the increase?" }] }
]
}'requireIdle: true rejects the POST if the session is already running — use it to prevent double-sends.
Advanced topics
Idempotency
Wrap every mutating call in an Idempotency-Key header (a UUID you generate once per logical operation). Replaying the same key returns the first response without side effects. Network timeouts are safe to retry with the same key.
curl -X POST https://api.agentsky.dev/v1/sessions \
-H "Authorization: Bearer ast_..." \
-H "Idempotency-Key: 40a9ae2a-4ea5-4a50-987e-d8b3c99c96f0" \
...Budgets and spending limits
Cap what a session may spend with a spend policy:
curl -X POST https://api.agentsky.dev/v1/sessions/sess_.../policies \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Spend cap",
"kind": "SPEND_CAP",
"config": { "hardCapUsdMicros": 5000000, "warnUsdMicros": 4000000 }
}'The session stops with stop_reason.type: "budget_reached" when the hard cap is reached. GET /v1/sessions/{id} includes cumulative spend.
Interrupts
Stop a running session gracefully:
curl -X POST https://api.agentsky.dev/v1/sessions/sess_.../events \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{ "events": [{ "type": "user.interrupt" }] }'Send "mode": "save" to ask the agent to save what it has and end the turn cleanly.
Reconnect and replay
Missed stream events are kept in the event log forever. Replay from any event ID:
# All events in order (same objects as the live stream; dedupe by event id)
curl "https://api.agentsky.dev/v1/sessions/sess_.../events" \
-H "Authorization: Bearer ast_..."
# Resume stream from a known event id
curl -N "https://api.agentsky.dev/v1/sessions/sess_.../stream?after=msg-77e0c4…" \
-H "Authorization: Bearer ast_..."Files and workspace
Upload files and mount them into a session:
# Upload
curl -X POST https://api.agentsky.dev/v1/files \
-H "Authorization: Bearer ast_..." \
-F "file=@report.pdf"
# → { "id": "file_…", … }
# Mount at session create or POST /sessions/{id}/resources
-d '{ "agent": "agent_…",
"resources": [
{ "type": "file", "file_id": "file_…", "mount_path": "/data/report.pdf" }
] }'GitHub repositories mount the same way ("type": "github_repository"); memory stores mount as "type": "memory_store".
Vaults and secrets
Store per-agent secrets (OAuth tokens, webhook signing keys) in the agent's vault:
curl -X PUT https://api.agentsky.dev/v1/agents/agent_.../secrets/MY_TOKEN \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{ "value": "secret_…" }'The agent sees the value as an environment variable; it never appears in API responses.
Webhooks
Subscribe to session events server-to-server:
curl -X POST https://api.agentsky.dev/v1/webhooks \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/agentsky",
"events": ["session.status_idle", "session.error"]
}'The routine_run.failed and routine.paused events are also available. Wire hook rules to call a URL or require human approval on specific tool uses (POST /hook_rules).
Environments (universes)
Create an isolated workspace for a customer, team, or environment:
curl -X POST https://api.agentsky.dev/v1/universes \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{ "slug": "acme", "name": "Acme" }'
# All subsequent calls scoped to that workspace:
curl ... -H "X-Universe: acme"Invite members (POST /universes/{slug}/invites), set policies, and pin agent versions (PUT /universes/{slug}/agents/{handle}).
Skills and agent.toml
Attach reusable instruction bundles to any agent with sky launch and an agent.toml file, or via PUT /agents/{id}/prompt. Skills are versioned bundles you upload once and attach by reference.
Agent identity fields (D-391)
Three optional fields let you give an agent a persistent identity within a workspace.
handle — workspace-scoped @-handle (lower-case, 2–40 chars: [a-z0-9_]). Unique within the workspace. Setting it gives the agent a stable email address and lets you start sessions with "agent": "@handle" instead of the agent id.
# Set a handle at create time
curl -X POST https://api.agentsky.dev/v1/agents \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{
"displayName": "Support Bot",
"handle": "support_bot"
}'
# → { "id": "agent_…", "handle": "support_bot",
# "email": "support_bot@agents.agentsky.dev", … }
# Or set/update it via PATCH
curl -X PATCH https://api.agentsky.dev/v1/agents/agent_... \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{ "handle": "support_bot" }'
# Start a session by handle
curl -X POST https://api.agentsky.dev/v1/sessions \
-H "Authorization: Bearer ast_..." \
-H "Content-Type: application/json" \
-d '{ "agent": "@support_bot", "initial_events": [] }'Pass "handle": null in PATCH to clear the handle.
email — read-only. Present in agent responses when a handle is set; value is {handle}@agents.agentsky.dev. The address is reserved, not live: agents.agentsky.dev has no mail receiving yet, so mail sent to it bounces, and agents have no tool to send from it.
channel_settings — Slack/Lark persona settings. Controls whether the agent is invitable to channels and carries an optional description.
{ "invitable": true, "description": "Handles tier-1 support tickets" }Pass "channel_settings": null to reset to defaults.
runtime — BYO-code runtime config. Two shapes:
{ "kind": "image", "image": "ghcr.io/your-org/agent@sha256:<64 hex>" }— run your own container image. The reference must be digest-pinned and readable anonymously from its registry (checked on create/PATCH,422 invalid_runtimeotherwise). The agent becomes aworkspace_acpagent on a hosted harness built from the image; sessions answer409 harness_not_readyuntil the image's template is built. The image must run the hosted-brain contract.{ "kind": "endpoint", "protocol": "a2a", "url": "https://…" }— AgentSky sends each user turn to your A2A agent asmessage/send(no sandbox, nothing metered) and shows its reply as the agent's turn. Set the agent secretA2A_AUTH_TOKENto have it sent asAuthorization: Bearer ….acpandmcpare refused with422 runtime_protocol_not_supported.
Note: BYO-code runtimes are enabled per workspace. Where they are not, session create answers
422 runtime_not_available.
Pass "runtime": null to clear (agent runs in the standard sandbox).
Reference
- Full API reference — every /v1 endpoint, schemas, the error contract, and the complete stream event catalog
- Authentication — tokens, scopes, X-Universe header
- Concepts — agents, sessions, events, and billing explained
- CLI —
sky launch,sky agent,sky sessionand every other command - agent.toml — declarative agent configuration
