> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sessions

> Create, run, inspect, and archive Cloud Agent Sessions.

A Session is a running workspace for an Agent. It binds an Agent snapshot to an Environment, optional resources, and optional Vault credentials. New Sessions start in `idle`; send events to start work.

## Session Status Lifecycle

A Session is a state machine. The `status` field on a Session resource takes one of the following values:

| Status         | Description                                                                                        | Transitions to                          |
| -------------- | -------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `idle`         | Session is idle and ready to receive a message                                                     | `running`, `rescheduling`, `terminated` |
| `running`      | Agent is processing a turn                                                                         | `idle`, `rescheduling`, `terminated`    |
| `rescheduling` | The underlying runtime is being rescheduled; the Session is unavailable until it returns to `idle` | `idle`, `terminated`                    |
| `terminated`   | Session has been terminated (final state)                                                          | —                                       |

Two additional lifecycle markers are surfaced outside the `status` field:

* **Archived**: signalled by a non-null `archived_at` timestamp. The `status` value itself does not change to `archived` — the Session remains readable but rejects new events.
* **Cancel response**: the `POST /api/v1/cloud/sessions/{id}/cancel` endpoint always returns a fixed body literal `"status": "canceling"`. This is a response shape, not a Session status — the persisted `status` reverts to `idle` once the turn aborts.

<Steps>
  <Step title="Created → idle">
    A new Session starts in `idle`, awaiting input.
  </Step>

  <Step title="idle → running">
    Sending a `user.message` event moves the Session into `running`.
  </Step>

  <Step title="running → idle">
    When the turn completes, the Session returns to `idle`. Repeat for each turn.
  </Step>

  <Step title="running → idle (after cancel)">
    Cancelling a running Session aborts the turn and the Session returns to `idle`. The cancel response body uses a fixed `"status": "canceling"` literal regardless of the persisted status. The Session remains reusable.
  </Step>

  <Step title="rescheduling">
    The runtime may temporarily move into `rescheduling` while the Session is being rescheduled; it returns to `idle` once recovery completes.
  </Step>

  <Step title="archived / terminated (terminal)">
    Archival (via `archived_at`) or termination ends the Session permanently — it cannot be resumed.
  </Step>
</Steps>

## Cancel Semantics

* **Cancel on `idle`**: No-op. Returns HTTP `200` and the status stays `idle`.
* **Cancel on `running`**: Interrupts the Agent. Returns HTTP `202`. The Session transitions to `canceling`, then back to `idle` once the turn aborts.
* **After cancel**: The Session remains reusable — send the next `user.message` to start a new turn.

```bash theme={null}
# Cancel the current turn
curl -s -X POST "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/cancel" \
  -H "Authorization: Bearer $QODER_PAT"
```

<Note>
  Only `archived` and `terminated` are terminal states. A cancelled Session always returns to `idle` and can continue accepting messages.
</Note>

## Sending Messages to a Running Session (409 Error)

If you send a `user.message` to a Session that is currently `running`, the API returns **HTTP 409**:

```json theme={null}
{
  "type": "error",
  "request_id": "cb80235f-76a2-4ff3-9e28-5aa2da12dc14",
  "error": {
    "type": "invalid_request_error",
    "message": "Session is currently processing a turn. Cancel the current turn or wait for completion."
  }
}
```

This is the most common pitfall for new users. Always wait for `session.status_idle` before sending the next message, or cancel the current turn first.

## Create a Session

Create a Session with an existing `agent` and `environment_id`:

```bash theme={null}
curl -s -X POST "https://api.qoder.com/api/v1/cloud/sessions" \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": {"id": "agent_019e390add9f7bac9b6cc806db46fcbd", "type": "agent", "version": 2},
    "environment_id": "env_019e2590d33f711fabf42f2857cecd8a",
    "title": "Code review session",
    "metadata": {"purpose": "review"}
  }'
```

The create response is a [Session object](/cloud-agents/api/sessions/schemas#session-object). It includes `agent`, `environment_id`, `status`, `resources`, `vault_ids`, `deployment_id`, `outcome_evaluations`, `stats`, `environment_variables`, `archived_at`, `created_at`, and `updated_at`.

Legacy request fields such as `environment`, `delta_flush_interval_ms`, `memory_store_ids`, and `vaults` are not supported. `environment_variables` is supported again — see [Create a session](/cloud-agents/api/sessions/create) for the JSON-string request format and validation rules.

## Attach Resources at Creation

Attach files, repositories, and Memory Stores in the `resources` array:

```json theme={null}
{
  "resources": [
    {
      "type": "file",
      "file_id": "file_019e5ce0bf307a1a8f952eb814aea3d5",
      "mount_path": "/data/input/spec.md"
    },
    {
      "type": "github_repository",
      "url": "https://github.com/your-org/your-repo",
      "mount_path": "/data/workspace/your-repo",
      "authorization_token": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    },
    {
      "type": "memory_store",
      "memory_store_id": "memstore_019eed05b61e78cea61bfd366e072878",
      "access": "read_write",
      "instructions": "Use this memory for long-lived project context."
    }
  ]
}
```

To add a file after creation, use [`POST /api/v1/cloud/sessions/{session_id}/resources`](/cloud-agents/api/sessions/add-resource). Current CAS supports post-create add only for file resources. Use the resource list/get/update/delete endpoints to inspect, rotate a GitHub token, or remove resources.

## Send Messages

Send `user.message` events through the Events API. `content` must be a non-empty array of content blocks:

```bash theme={null}
curl -s -X POST "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/events" \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "type": "user.message",
        "content": [
          {"type": "text", "text": "Review this repository and summarize the risks."}
        ]
      }
    ]
  }'
```

The send-events endpoint returns **HTTP 200** with `{"data":[...]}`. It accepts these client event types: `user.message`, `user.interrupt`, `user.tool_confirmation`, `user.tool_result`, `user.custom_tool_result`, `user.define_outcome`, and `system.message`.

## Read Events

Use the event stream for live updates:

```bash theme={null}
curl -s -N "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/events/stream" \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Accept: text/event-stream"
```

The stream emits Server-Sent Events with `id`, `event`, and `data`. The stream endpoint supports the `Last-Event-ID` header for reconnection replay; event type query filters are not currently supported.

To receive incremental streaming events, set `incremental_streaming_enabled: true` when creating the Session. The stream can then include `agent.message_start`, `agent.content_block_delta`, and related incremental events before the final full `agent.message`. See [Incremental streaming](/cloud-agents/incremental-streaming) for a quick verification flow.

Use the list endpoint for history and pagination:

```bash theme={null}
curl -s "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/events?limit=20&order=desc" \
  -H "Authorization: Bearer $QODER_PAT"
```

List responses use `data` and `next_page`.

## Read and Update Sessions

```bash theme={null}
# Get one Session
curl -s "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $QODER_PAT"

# List Sessions
curl -s "https://api.qoder.com/api/v1/cloud/sessions?limit=20" \
  -H "Authorization: Bearer $QODER_PAT"

# Update title, metadata, or Agent configuration (tools, MCP servers)
curl -s -X POST "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Content-Type: application/json" \
  -d '{"title":"Updated title","metadata":{"priority":"high"}}'
```

Session list uses `page` / `next_page` pagination and supports filters such as `agent_id`, `agent_version`, `deployment_id`, `memory_store_id`, `statuses`, and `created_at[...]`.

## Threads

Managed-agent Sessions can have a coordinator thread and child threads. Thread endpoints use the public `session_thread` shape and do not include legacy thread fields such as `role`, `name`, `agent_id`, `agent_version`, or `stop_reason`.

```bash theme={null}
curl -s "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/threads" \
  -H "Authorization: Bearer $QODER_PAT"
```

Child threads can be archived with `POST /api/v1/cloud/sessions/{session_id}/threads/{thread_id}/archive`. Current CAS returns `409` when asked to archive the coordinator/main thread.

## Lifecycle

Archive a Session when it should no longer be used:

```bash theme={null}
curl -s -X POST "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/archive" \
  -H "Authorization: Bearer $QODER_PAT"
```

Delete a Session when you need removal confirmation:

```bash theme={null}
curl -s -X DELETE "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $QODER_PAT"
```

Delete returns:

```json theme={null}
{
  "id": "sess_019e3bb1e8c171fd9abbb1477ffb84cc",
  "type": "session_deleted"
}
```

The cancel endpoint returns `{"id":"...","type":"session","status":"canceling"}`. It responds with **202 Accepted** when there is an active turn to cancel, and **200 OK** (no-op) when the Session is already `idle`.

## Multi-Turn Conversation Workflow

Sessions support multi-turn conversations. The recommended pattern is:

1. Send a `user.message` event.
2. Listen to the SSE stream for updates.
3. Wait for the `session.status_idle` event.
4. Send the next `user.message`.

```bash theme={null}
#!/bin/bash
# Multi-turn conversation example
BASE_URL="https://api.qoder.com/api/v1/cloud"
SESSION_ID="sess_019e5ce0bf9074b69c3481e93771a522"
HEADERS=(
  -H "Authorization: Bearer $QODER_PAT"
)

# Turn 1: state the requirement
curl -s -X POST "$BASE_URL/sessions/$SESSION_ID/events" \
  "${HEADERS[@]}" \
  -H "Content-Type: application/json" \
  -d '{"events": [{"type": "user.message", "content": [{"type": "text", "text": "Scaffold a Python Flask project."}]}]}'

# Wait for processing to complete (poll or listen on SSE)
sleep 30

# Turn 2: add follow-up requirements
curl -s -X POST "$BASE_URL/sessions/$SESSION_ID/events" \
  "${HEADERS[@]}" \
  -H "Content-Type: application/json" \
  -d '{"events": [{"type": "user.message", "content": [{"type": "text", "text": "Add unit tests and a CI configuration to the project."}]}]}'
```

<Note>
  Always wait for `session.status_idle` before sending the next message. Sending a message while the Session is still `running` returns HTTP 409.
</Note>

## Best practices

1. **Pin Agent versions** — In production, always create Sessions with `{"id": ..., "type": "agent", "version": ...}` so Agent updates do not change Session behavior unexpectedly.
2. **Use metadata** — Record business context (task ID, trigger source, etc.) in the `metadata` field for traceability and debugging.
3. **Cancel promptly** — Cancel Sessions you no longer need to free compute resources.

## FAQ

**Q: What happens if I send a message to a `running` Session?**

A: The API returns **HTTP 409** with `type: "invalid_request_error"` and the message *"Session is currently processing a turn. Cancel the current turn or wait for completion."* Either cancel the current turn or wait until the Session returns to `idle` before sending the next message.

**Q: Can I still use a Session after cancelling?**

A: Yes. After cancel, the Session transitions from `canceling` back to `idle`. You can continue the conversation by sending the next `user.message`. Only `archived` and `terminated` are terminal states.

**Q: How do I get the full conversation history?**

A: Use `GET /api/v1/cloud/sessions/{id}/events` to retrieve all events for the Session, including user messages and Agent responses.

**Q: How do I reconnect after an SSE disconnect?**

A: Pass the `Last-Event-ID` header when reconnecting to the SSE stream endpoint. The server will replay events from after that ID.

**Q: `GET /api/v1/cloud/environments` returns an empty array?**

A: Check that your Personal Access Token (PAT) has the required permissions for the target workspace. Environment access is scoped to the authenticated user's permissions.

## API Reference

* [Create a session](/cloud-agents/api/sessions/create)
* [Send events](/cloud-agents/api/sessions/send-event)
* [List events](/cloud-agents/api/sessions/list-events)
* [Stream events](/cloud-agents/api/sessions/stream-events)
* [List Session resources](/cloud-agents/api/sessions/list-resources)
* [List Session threads](/cloud-agents/api/sessions/list-threads)
* [Session schemas](/cloud-agents/api/sessions/schemas)
