# 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](https://agentsky.dev/docs/gateway.md) instead — no sessions, no agents, same key). Or if you want to use agents from an MCP client (see [MCP server](https://agentsky.dev/docs/mcp.md)).

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 stream
```

An **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

```bash
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

```bash
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

```bash
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

```bash
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.

```bash
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:

```bash
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:

```bash
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:

```bash
# 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:

```bash
# 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:

```bash
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:

```bash
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:

```bash
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](https://agentsky.dev/docs/agent-toml.md) file, or via `PUT /agents/{id}/prompt`. [Skills](https://agentsky.dev/docs/skills.md) are versioned bundles you upload once and attach by reference.

## Reference

- [Full API reference](https://agentsky.dev/docs/api.md) — every /v1 endpoint, schemas, the error contract, and the complete stream event catalog
- [Authentication](https://agentsky.dev/docs/authentication.md) — tokens, scopes, X-Universe header
- [Concepts](https://agentsky.dev/docs/concepts.md) — agents, sessions, events, and billing explained
- [CLI](https://agentsky.dev/docs/cli.md) — `sky launch`, `sky agent`, `sky session` and every other command
- [agent.toml](https://agentsky.dev/docs/agent-toml.md) — declarative agent configuration
