---
title: "작업 세션"
description: "Alpacon 작업 세션 API의 생성, 승인, 수정과 연장 방법을 설명합니다. 사용자와 토큰별 권한, 상태 전환 조건, 승인 대기 응답을 확인하세요. 타임라인과 녹화 기록의 커서 페이지 이동, 요금제별 감사 기록 조회 기간, 요청 필드와 오류 코드도 함께 안내합니다."
---

> Full documentation index: https://docs.alpacax.com/llms.ko.txt

# 작업 세션

**엔드포인트**: `/api/work-sessions/sessions/`

사용자나 토큰이 정해진 범위에서 작업할 세션을 생성하고, 승인 상태와 작업 기록을 조회합니다. 서비스 토큰은 작업 세션을 생성할 수 없습니다. 사용자가 세션을 만들면서 `assigned_service_token`으로 해당 토큰에 배정해야 합니다. 서비스 토큰으로 자동화 작업을 실행할 때 작업 세션은 필수가 아닙니다.

## 접근 권한

슈퍼유저는 모든 세션을 조회하고 관리할 수 있습니다. 그 외에는 배정된 사용자, 배정된 개인 토큰의 소유자, 배정된 서비스 토큰이 속한 애플리케이션의 소유자가 세션을 관리할 수 있습니다. 서버나 클러스터의 소유자와 관리자는 해당 대상이 포함된 세션을 조회할 수 있습니다. 이들에게는 타임라인, 녹화 기록, 실시간 현황에서도 자신이 소유하거나 관리하는 대상의 작업만 표시됩니다.

개인 API 토큰에는 해당 작업의 `work_session` scope가 있어야 하며, 토큰 소유자에게도 세션 접근 권한이 있어야 합니다. 개인 API 토큰으로 생성하면 `requester_type`은 `agent`로 설정됩니다. 에이전트는 `websh`, `kube_exec` 프리셋을 사용할 수 없습니다. 서비스 토큰의 조회에도 세션 조회 권한, 토큰 scope, 감사 기록 조회 기간이 적용됩니다.

승인과 거부는 웹 콘솔에서만 가능합니다. 개인 토큰, 서비스 토큰, CLI, MCP 요청은 `403 permission_denied`를 반환합니다. 철회는 슈퍼유저만 할 수 있으며, 개인 토큰도 소유자가 슈퍼유저인 경우에만 철회할 수 있습니다. 취소는 생성자나 슈퍼유저만 할 수 있습니다. 세션을 배정받았다는 이유만으로 취소할 수는 없습니다. 개별 scope가 부여된 토큰으로는 취소, 실시간 현황 조회, 권고 사항 확인을 호출할 수 없습니다.

## 경로

아래 경로는 모두 `/api/work-sessions/sessions/`로 시작합니다. `{id}`는 작업 세션 UUID입니다.

| 메서드 | 뒤에 붙는 경로 | 성공 응답 | 토큰 scope 또는 접근 조건 |
|--------|---------------|-----------|--------------------------|
| `GET` | 없음 | `200`, 페이지로 나눈 세션 목록 | `work_session:read` |
| `POST` | 없음 | `201`, 세션 | `work_session:create`; 서비스 토큰 불가 |
| `GET` | `{id}/` | `200`, 세션 | `work_session:read` |
| `PUT`, `PATCH` | `{id}/` | `200` 또는 `202`, 세션 | `work_session:update`; 관리 권한 |
| `POST` | `{id}/activate/` | `200`, 세션 | `work_session:activate`; 관리 권한 |
| `POST` | `{id}/complete/` | `200`, 세션 | `work_session:complete`; 관리 권한 |
| `POST` | `{id}/revoke/` | `200`, 세션 | `work_session:revoke`; 슈퍼유저 |
| `POST` | `{id}/cancel/` | `200`, 세션 | 로그인한 생성자 또는 슈퍼유저. 개별 scope 토큰은 거부 |
| `POST` | `{id}/approve/` | `200`, 세션 또는 추가 승인 대기 | 웹 콘솔의 승인자 |
| `POST` | `{id}/reject/` | `200`, 세션 | 웹 콘솔의 승인자 |
| `POST` | `{id}/extend/` | `200` 또는 `202`, 세션 | `work_session:extend`; 관리 권한 |
| `GET` | `{id}/timeline/` | `200`, 타임라인 | `work_session:timeline` |
| `GET` | `{id}/records/` | `200`, 녹화 기록 조각 | `work_session:timeline`; 유료 요금제 |
| `GET` | `{id}/live_snapshot/` | `200`, 실시간 현황 | 조회 권한이 있는 로그인 세션. 개별 scope 토큰은 거부 |
| `POST` | `{id}/analyze/` | `200` 또는 `202` | `work_session:analyze`; 관리 권한과 유료 요금제 |
| `POST` | `{id}/acknowledge-recommendations/` | `200`, 확인 시각 | 로그인한 배정 사용자. 개별 scope 토큰은 거부 |
| `POST` | `suggest-scopes/` | `200`, 추천 결과 | `work_session:suggest_scopes` |
| `POST` | `resolve-target-account/` | `200`, 계정 사전 확인 결과 | `work_session:resolve_target_account`와 `proc:read`; 서비스 토큰 불가 |
| `POST` | `candidate-target-accounts/` | `200`, 후보 계정 | `work_session:candidate_target_accounts`와 `proc:read`; 서비스 토큰 불가 |

`DELETE`는 지원하지 않으며 `405`를 반환합니다. 예약된 세션은 자동으로 활성화됩니다. `activate`는 승인된 세션을 예정 시각보다 일찍 시작할 때만 필요합니다.

## 상태 흐름

| 상태 전환 | 조건과 수행 주체 |
|-----------|------------------|
| 생성 → `active` | 승인이 필요 없고 시작 시각이 미래가 아님 |
| 생성 → `approved` | 승인이 필요 없고 `starts_at`이 미래임 |
| 생성 → `pending` | 승인 필요 |
| `pending` → `active` 또는 `approved` | 승인자가 웹 콘솔에서 승인을 완료함. 미래에 시작하는 세션은 `approved` |
| `pending` → `rejected` | 승인자가 웹 콘솔에서 거부 |
| `pending` → `cancelled` | 생성자나 슈퍼유저가 취소하거나, 승인 요청 기한 또는 만료 시각에 도달 |
| `approved` → `active` | 시작 시각에 도달하거나 관리 권한이 있는 사용자가 activate 호출 |
| `active` → `completed` | 관리 권한이 있는 사용자가 complete 호출 |
| `approved` 또는 `active` → `revoked` | 슈퍼유저가 철회 |
| `approved` 또는 `active` → `expired` | 만료 시각 도달 |

완료, 만료, 철회, 거부, 취소된 세션은 수정할 수 없습니다. 세션이 종료되면 대기 중인 수정 요청도 취소되고 연결이 닫힙니다. `duration`을 지정한 세션은 활성화 전까지 `expires_at`이 null이며, 활성화되면 `started_at + duration`으로 설정됩니다.

## 세션 생성

```http
POST /api/work-sessions/sessions/
```

| 필드 | 유형 | 필수 | 설명 |
|------|------|------|------|
| `title` | 문자열 | 아니요 | 최대 128자, 기본값은 빈 문자열 |
| `description` | 문자열 | 예 | 작업 목적, 최대 2,048자 |
| `requester_type` | 문자열 | 예 | `user` 또는 `agent`. 자동화 채널에서는 `agent`로 설정 |
| `scopes` | 문자열 배열 | 예 | 비어 있지 않은 프리셋 목록: `websh`, `tunnel`, `editor`, `webftp`, `command`, `sudo`, `kube`, `kube_exec` |
| `servers` | UUID 배열 | 대상 유형 중 하나 | 조회 가능한 서버 ID 최대 100개. `id`가 담긴 객체도 허용 |
| `clusters` | UUID 배열 | 대상 유형 중 하나 | 클러스터 최대 1개. Kubernetes를 사용할 수 있는 환경에서 `kube`를 포함한 Kubernetes 프리셋만 지정 |
| `target_account_username` | 문자열 | 아니요 | 출력 가능한 ASCII 문자 최대 128자. 공백, `:`, `/` 불가. 기본값은 배정된 사용자의 username. 토큰에 배정된 세션이나 클러스터 세션에서는 사용 불가 |
| `assigned_user` | 사용자 ID | 아니요 | 기본값은 요청자 |
| `assigned_token` | UUID | 아니요 | 사용자 대신 개인 API 토큰에 배정 |
| `assigned_service_token` | UUID | 아니요 | 사용자 대신 서비스 토큰에 배정 |
| `duration` | 기간 | 시간 제한 중 하나 | `01:00:00`과 같은 양수 기간. 워크스페이스의 최대 세션 기간 이내 |
| `expires_at` | 날짜와 시간 | 시간 제한 중 하나 | 최대 세션 기간 이내의 미래 만료 시각, ISO 8601 형식 |
| `starts_at` | 날짜와 시간 | 아니요 | 만료 전의 미래 시작 시각. 기본값 null이면 승인 즉시 활성화 |
| `sudo_policies` | 객체 배열 | 아니요 | 최대 10개. `sudo` 프리셋 필요 |

서버와 클러스터 중 하나, 배정 대상 하나, `duration`과 `expires_at` 중 하나를 선택하세요. 슈퍼유저가 아닌 사용자는 본인, 본인의 개인 토큰, 본인이 소유한 애플리케이션의 서비스 토큰에만 배정할 수 있습니다. 기본 최대 세션 기간은 4시간입니다. `request_channel`과 `declared_agent`는 읽기 전용입니다.

각 sudo 정책에는 비어 있지 않은 `commands`(항목당 최대 512자), 선택 필드인 `users`, `allow_bypass_mfa`(기본값 false, 세션 승인이 sudo MFA를 대신하도록 허용), `reason`(최대 1,024자), `valid_until`을 지정합니다. 슈퍼유저가 아닌 사용자는 `users`에 배정된 사용자만 지정할 수 있습니다. 실행 채널에서 세션 승인이 sudo MFA를 대신하는 정책을 변경하면 승인이 필요하거나 아래 오류로 거절될 수 있습니다.

예를 들어 `work_session:create`가 있는 개인 토큰으로 소유자가 로그인한 CLI 또는 MCP 세션에서 사용할 에이전트 명령 세션을 요청합니다. 개인 토큰에는 명령 실행 scope를 발급할 수 없으므로, 개인 토큰 자체로는 이 세션에서 명령을 실행할 수 없습니다.

```bash
curl -X POST "https://your-workspace.ap1.alpacon.io/api/work-sessions/sessions/" \
  -H "Authorization: token=\"alpat-xxxxxxxxxxxxxxxxxx\"" \
  -H "Content-Type: application/json" \
  -d '{"description":"Check disk space before deployment","requester_type":"agent","scopes":["command"],"servers":["7e3984de-49ab-4cc6-bcdf-21fbd35858b8"],"duration":"01:00:00"}'
```

생성에 성공하면 승인 필요 여부와 관계없이 `201`을 반환합니다. 승인이 필요하면 세션의 `status`는 `"pending"`이며 `approval_request_id`가 설정됩니다. 상세 조회로 상태가 바뀔 때까지 확인하세요. HTTP 요청이 성공했다고 해서 세션을 바로 사용할 수 있는 것은 아닙니다.

```bash
curl "https://your-workspace.ap1.alpacon.io/api/work-sessions/sessions/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: token=\"alpat-xxxxxxxxxxxxxxxxxx\""
```

상태 조회에 사용하는 토큰에는 `work_session:read`가 필요합니다. Free 요금제에서 다른 대상에 배정한 결과 생성자가 세션을 조회할 수 없게 되면 `402 workspace_plan_update_required`를 반환합니다.

## 수정과 연장

```http
PATCH /api/work-sessions/sessions/{id}/
PUT /api/work-sessions/sessions/{id}/
POST /api/work-sessions/sessions/{id}/extend/
```

승인 대기 중인 세션은 `title`, `description`, `scopes`, `servers`, `clusters`, `target_account_username`, `starts_at`, `expires_at`을 수정할 수 있습니다. 변경 사항은 바로 적용되며 승인 요청을 다시 평가합니다. 배정 대상은 바꿀 수 없으며, 지정한 계정을 빈 값으로 지울 수도 없습니다.

승인되었거나 활성 상태인 세션은 `title`, `description`, `scopes`, `servers`, `target_account_username`, `sudo_policies`를 수정할 수 있습니다. sudo 정책은 최종적으로 적용할 전체 목록을 보내세요. 기존 항목에는 `id`를 포함할 수 있습니다. 항목을 제거하거나 허용 범위를 줄이는 변경, 웹 콘솔에서의 제목 변경은 즉시 적용됩니다. 설명 변경, scope나 서버 추가, sudo 정책의 허용 범위 확대, 계정 변경에는 승인이 필요합니다. 수정 요청은 한 번에 하나만 대기할 수 있습니다.

즉시 적용한 수정은 `200`, 승인 대기 중인 수정은 전체 세션과 함께 `202`를 반환합니다. `pending_modification_request` 형식은 다음과 같습니다.

```json
{
  "id": "9b52a7c4-13de-48f6-a01b-7f3e5d982c44",
  "changes": {},
  "added_at": "2026-10-24T10:00:00Z",
  "can_cancel": true
}
```

세션을 연장하려면 현재보다 늦은 `expires_at`과 공백이 아닌 최대 2,048자의 `reason`을 보냅니다. 세션은 승인되었거나 활성 상태여야 하며, 시작 시각이 지났고 아직 만료되지 않아야 합니다. 새 만료 시각도 현재부터 워크스페이스의 최대 세션 기간 이내여야 합니다.

```json
{
  "expires_at": "2026-10-24T12:00:00Z",
  "reason": "Finish deployment verification"
}
```

즉시 적용한 연장은 `200`, 승인이 필요한 연장은 전체 세션과 함께 `202`를 반환합니다. 연장 요청은 한 번에 하나만 대기할 수 있습니다. `pending_extension_request` 형식은 다음과 같습니다.

```json
{
  "id": "9b52a7c4-13de-48f6-a01b-7f3e5d982c44",
  "requested_expires_at": "2026-10-24T12:00:00Z",
  "expires_at": "2026-10-24T11:00:00Z",
  "reason": "Finish deployment verification",
  "added_at": "2026-10-24T10:00:00Z"
}
```

여기서 `expires_at`은 연장 요청의 기한이며, 세션의 현재 만료 시각을 넘지 않습니다. 연장 전에 상세 응답의 `can_extend`, `extend_blocked_reason`, `max_extendable_to`, `extension_request_deadline`, `extension_ends_with_session`을 확인하세요. 목록 응답에서는 이 값들이 null입니다.

이 페이지의 승인 관련 변경 중 `202`를 반환하는 것은 수정과 연장뿐입니다. 생성은 승인 대기 상태여도 `201`을 반환합니다. 분석은 별도로 비동기 작업 접수에 `202`를 사용합니다.

## 승인과 기타 작업

승인 권한이 있는 사용자가 웹 콘솔에서 승인하거나 거부합니다. 정책에 따라 요청자는 자신의 요청을 승인할 수 없습니다. 새로운 MFA 인증이 필요하면 이 경로들은 `source` 필드 없이 `400 auth_mfa_required`를 반환합니다.

승인 요청에는 선택 필드로 `adjusted_scopes`(비어 있지 않은 유효한 프리셋 목록), `adjusted_servers`(UUID 최대 100개, 범위 축소만 가능), `adjusted_target_account_username`(공백 불가, 범위 축소만 가능)을 보낼 수 있습니다. 시간 조정은 `adjusted_duration`(양의 정수 초)과 `adjusted_expires_at`(미래 시각) 중 하나를 사용합니다. 선택 필드 `recommendations`는 `id`, `text`, `severity`(`low`, `medium`, `high`), `source`(`ai_suggested`, `ai_edited`, `admin_added`), `auto_checkable`(불리언)이 담긴 객체 배열입니다. `sudo_auto_approve: true`는 거절하며, `sudo_risk_ceiling`은 받지만 적용하지 않습니다.

승인자에게 세션 조회 권한이 없으면 이 경로는 `404`를 반환합니다. 이때는 승인 요청에 대해 `POST /api/approvals/approvals/{id}/approve/`를 사용해야 합니다.

승인이 완료되면 세션을 반환합니다. 추가 승인이 필요하면 `200`과 함께 다음을 반환합니다.

```json
{"status":"pending","approvals_received":1,"approvals_required":2}
```

거부와 취소는 세션을 반환합니다. 취소하려면 승인 대기 상태여야 합니다. 완료는 활성 상태에서만 가능하며 분석을 시작합니다. 철회는 승인 또는 활성 상태에서 가능합니다. 활성화는 승인된 미만료 세션에 사용할 수 있으며, 이미 활성 상태여도 성공합니다.

`POST {id}/acknowledge-recommendations/`는 여러 번 호출해도 같은 결과를 반환하며, 응답은 `{"recommendations_acknowledged_at":"2026-10-24T10:00:00Z"}`입니다. 배정된 사용자만 확인할 수 있습니다.

`POST {id}/analyze/`는 `completed`, `expired`, `revoked` 상태에서 사용할 수 있습니다. `202 {"status":"accepted","work_session":"SESSION_ID"}` 또는 `status: "already_exists"`가 있는 `200`을 반환합니다. `?force=true`는 대기 또는 처리 상태에서 멈춘 분석이 재시도 가능한 시간이 지났을 때 다시 시도합니다. 유료 요금제가 필요합니다.

## 세션 목록과 상세 조회

```http
GET /api/work-sessions/sessions/
GET /api/work-sessions/sessions/{id}/
```

| 매개변수 | 설명 |
|----------|------|
| `status` | 쉼표로 구분한 세션 상태 |
| `request_channel` | 쉼표로 구분한 `cli`, `mcp`, `api_token`, `service_token`, `unknown`, `unknown_client`, `web` |
| `scopes` | 쉼표로 구분한 프리셋. 하나라도 겹치면 포함 |
| `requester_type` | 요청자 유형과 정확히 일치 |
| `server`, `cluster`, `assigned_user` | UUID로 필터링 |
| `start`, `end` | 생성 시각의 시작과 끝. ISO 8601 형식이며 양쪽 경계 포함 |
| `has_attention` | 불리언. 실시간 요약도 함께 활성화 |
| `analysis_status` | `pending`, `processing`, `completed`, `failed` |
| `analysis_ended_at__gte`, `analysis_ended_at__lt` | 분석 완료 시각의 하한(포함)과 상한(미포함) |
| `search` | 제목, 설명, 서버와 클러스터 이름 검색 |
| `ordering` | `added_at`, `expires_at`, `starts_at`, `started_at`, `status`, `attention`. 기본값 `-added_at`. `attention`은 첫 번째 정렬 기준으로만 사용하며 실시간 요약을 활성화 |
| `include` | `live_summary`로 설정하면 각 항목에 실시간 요약 포함 |
| `page`, `page_size` | 정수 페이지 번호. 기본 크기 15, 최대 100, 초과 값은 100으로 제한 |

알 수 없는 상태, 채널, 프리셋은 `400 invalid_input`을 반환합니다.

```json
{"count":0,"current":1,"next":null,"previous":null,"last":1,"results":[]}
```

`results`에는 세션 객체가 들어갑니다. `next`와 `previous`는 정수 페이지 번호 또는 `null`입니다.

### 세션 필드

| 필드 | 설명 |
|------|------|
| `id`, `title`, `description`, `status` | 식별자, 목적, 현재 상태 |
| `requester_type`, `request_channel`, `requester_type_verified`, `declared_agent` | 요청자와 채널 정보 |
| `scopes`, `servers`, `clusters` | 허용된 작업과 대상. 각 서버에는 `id`, `name`, `os`, `platform`, `is_connected`, `is_deleted` 포함 |
| `target_account_username`, `target_account_is_self`, `account_flag` | 대상 계정 정보 |
| `created_by`, `assigned_user`, `assigned_token`, `assigned_service_token`, `assigned_credential` | 생성자와 배정 대상. 관리 권한이 없으면 `assigned_credential`은 null |
| `starts_at`, `expires_at`, `duration`, `started_at`, `completed_at` | 요청한 시간 범위와 실제 작업 시각 |
| `approval_request_id`, `admission_decision`, `adjustments` | 승인과 조정 내역 |
| `pending_modification_request`, `pending_extension_request` | 위 형식의 대기 중인 변경 요청 |
| `sudo_policies`, `proposed_sudo_policies`, `sudo_auto_approve`, `sudo_risk_ceiling`, `sudo_posture` | sudo 설정. 연결된 정책에는 `id`, `commands`, `allow_bypass_mfa`, `reason`, `valid_from`, `valid_until` 포함 |
| `ai_suggestion`, `recommendations`, `recommendations_acknowledged_at` | 추천 내용과 확인 시각 |
| `analysis`, `can_analyze`, `can_manage` | 분석은 null 또는 `id`, `status`, `risk_score` 객체. 수행 가능한 작업 정보 |
| `can_extend`, `extend_blocked_reason`, `max_extendable_to`, `extension_request_deadline`, `extension_ends_with_session` | 상세 조회와 실시간 현황에 포함되는 연장 안내 정보 |
| `live_summary` | 요청한 경우 포함되는 실시간 요약 |
| `added_at`, `updated_at` | 생성과 수정 시각 |

## 타임라인과 녹화 기록

이 경로들은 위 정수 페이지 번호 대신 각각의 커서 형식을 사용합니다.

### 타임라인

```http
GET /api/work-sessions/sessions/{id}/timeline/
GET /api/work-sessions/sessions/{id}/timeline/?cursor=&page_size=100
```

`cursor`가 없으면 전체 세션을 `{"results":[...]}` 형식으로 반환합니다. `include_records`의 기본값은 true이며, `0`, `false`, `no`로 녹화 기록을 제외할 수 있습니다. 포함되는 녹화 기록은 응답당 2 MiB, Websh 세션당 128 KiB로 제한됩니다. Free 요금제에서는 각 녹화 기록의 시작 부분만 반환합니다. 이 형식에서 `page_size`는 적용되지 않습니다.

값이 비어 있어도 `cursor`를 포함하면 앞으로 이동하는 커서 페이지 형식을 사용합니다.

```json
{"next":"OPAQUE_CURSOR","results":[]}
```

반환된 값을 다음 요청의 `cursor`로 보내고, `next`가 null이면 종료합니다. `count`와 `previous`는 없습니다. `page_size`의 기본값은 100이며 1–500 사이의 정수여야 합니다. 잘못된 값이나 범위를 벗어난 값은 `400 invalid_input`을 반환합니다. 다른 워크스페이스, 세션, 접근 범위의 커서는 `400 api_invalid_cursor`를 반환합니다.

모든 항목에는 `type`, `timestamp`, `id`, `server_id`가 있습니다. 유형은 `command`, `websh_session`, `tunnel_session`, `websh_record`, `ftp_session`, `file_upload`, `file_download`, `sudo_grant`, `kube_request`입니다. 시간순으로 정렬하며 같은 시각이면 위 유형 순서를 따릅니다. 명령 항목에는 `masked_output_summary`(최대 200자)와 `output_truncated`가 있습니다. 커서 페이지에는 녹화 데이터가 들어 있지 않습니다. `websh_session` 항목의 `record_chunks_total`로 조각 수를 확인하고 따로 조회하세요.

### 녹화 기록 조각

```http
GET /api/work-sessions/sessions/{id}/records/?session={websh_session_id}
```

필수 매개변수 `session`에는 이 작업 세션에 속한 Websh 세션 UUID를 지정합니다. 터널 세션은 사용할 수 없습니다. 유료 요금제가 필요합니다.

```json
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [{"added_at":"2026-10-24T10:00:00Z","record":"masked terminal output"}]
}
```

`next`와 `previous`는 불투명한 커서 문자열 또는 null입니다. 이동할 커서를 `cursor`에 보내세요. `cursor=last`는 마지막 페이지부터 조회합니다. `page_size`는 기본값 8, 최대 16입니다. 잘못된 값은 기본값을 사용하고 큰 값은 최댓값으로 제한합니다. 응답 크기도 2 MiB로 제한되므로 요청한 수보다 적은 조각을 받을 수 있습니다. `next`로 이어서 조회하세요. 만료된 커서는 `400 api_cursor_expired`, 잘못된 커서는 `400 api_invalid_cursor`를 반환합니다. 기록 검색을 사용할 수 없으면 `503 api_search_unavailable`을 반환합니다.

### 실시간 현황

```http
GET /api/work-sessions/sessions/{id}/live_snapshot/
```

조회 권한이 있는 로그인 세션을 사용합니다. `since`는 시간대 오프셋을 포함한 ISO 8601 날짜와 시간을 받습니다. `limit`의 기본값과 최댓값은 200이며, 정수가 아니면 `400 invalid_input`을 반환합니다. 응답에는 `work_session`, `last_seq`, `snapshot_taken_at`, `status_history`, `commands`, `websh_sessions`, `sudo_grants`, `ftp_events`가 포함됩니다.

## 작업 계획 보조 API

| 경로 | 요청 | 응답 |
|------|------|------|
| `POST /api/work-sessions/sessions/suggest-scopes/` | 필수 `description`(최대 2,048자), 비어 있지 않은 `servers`. 선택 필드 `requester_type`(기본값 `user`), `proposed_sudo_policies`, `include_improved_description`(기본값 false) | `suggested_scopes`, `risk_level`, `reasoning`, `improved_description`, `sudo_policy_assessments` |
| `POST /api/work-sessions/sessions/resolve-target-account/` | 필수 `servers`. 선택 필드 `assigned_user`, `target_account_username`(기본값은 배정된 사용자의 username) | 계정 사전 확인 결과: `version`, `account`, `is_self`, `is_own_username`, `lane`, `reason`, `role_reach`, `servers` |
| `POST /api/work-sessions/sessions/candidate-target-accounts/` | 필수 `servers`. 선택 필드 `assigned_user` | `server_count`, `accounts` |

계정 보조 API는 서비스 토큰을 받지 않습니다. 슈퍼유저가 아닌 사용자는 `assigned_user`에 본인만 지정할 수 있습니다. 개인 토큰에는 해당 경로의 `work_session` scope와 `proc:read`가 모두 필요합니다. AI를 사용할 수 없으면 scope 추천은 `400 work_session_ai_unavailable`을 반환합니다.

## 감사 기록 조회 기간과 요금제

감사 기록 조회 기간은 Free 7일, Essentials 120일, Enterprise 365일입니다. 목록에는 이보다 오래된 세션이 나타나지 않습니다. Free에서는 본인의 세션만 목록에 표시됩니다. Essentials와 Enterprise에서는 기존 조회 권한 범위에서 조직의 기록을 조회할 수 있습니다. 서비스 토큰도 자신의 조회 권한과 요금제의 기간 제한 안에서 조직 범위의 감사 기록을 조회합니다.

Free 요금제에서 다른 사용자의 세션 상세, 타임라인, 녹화 기록, 실시간 현황을 요청하면 `404 api_not_found`를 반환합니다. 조회 권한이 있는 세션이라도 감사 기록 조회 기간을 벗어나면 `402 workspace_plan_update_required`를 반환합니다. 기간 안에 있더라도 녹화 기록과 분석에는 유료 요금제가 필요합니다.

## 오류

| 상태 | 코드 | 의미 |
|------|------|------|
| `400` | `work_session_principal_not_supported` | 서비스 토큰으로 생성 또는 계정 보조 API 호출 |
| `400` | `work_session_invalid_scope`, `work_session_scope_not_allowed` | 잘못된 프리셋 또는 에이전트가 사용할 수 없는 프리셋 |
| `400` | `work_session_no_servers`, `work_session_mixed_targets`, `work_session_too_many_clusters`, `cluster_not_found` | 잘못된 대상 |
| `400` | `server_invalid`, `server_not_identified`, `server_not_found`, `server_too_many`, `server_access_denied` | 서버가 잘못되었거나 너무 많거나 접근 불가 |
| `400` | `work_session_multiple_assignees`, `work_session_assignee_not_allowed` | 배정 대상 중복 또는 허용되지 않은 배정 |
| `400` | `work_session_duration_or_expires_required`, `work_session_duration_and_expires_exclusive`, `work_session_duration_not_positive` | 기간 또는 만료 시각 지정 오류 |
| `400` | `work_session_expired`, `work_session_starts_at_in_past`, `work_session_starts_at_after_expires`, `work_session_expires_exceeds_max_ttl` | 잘못된 시간 범위 |
| `400` | `work_session_sudo_policy_without_scope`, `work_session_sudo_policy_user_not_assigned`, `work_session_sudo_policy_too_many`, `work_session_sudo_policy_id_not_bound` | 잘못된 sudo 정책 요청 |
| `400` | `work_session_target_account_invalid`, `work_session_target_account_not_applicable`, `work_session_target_account_clear_forbidden`, `work_session_target_account_absent`, `work_session_target_account_unavailable`, `work_session_target_account_not_reachable`, `target_account_other_person` | 대상 계정이 잘못되었거나, 없거나, 사용할 수 없거나, 다른 사람의 계정임 |
| `400` | `work_session_admission_denied` | 정책이 세션을 거절함 |
| `400` | `work_session_not_pending`, `work_session_not_active`, `work_session_not_approved`, `work_session_not_started`, `work_session_not_terminal`, `work_session_not_modifiable` | 현재 상태에서는 수행 불가 |
| `400` | `work_session_mod_no_changes`, `work_session_mod_already_pending` | 수정 사항이 없거나 다른 수정 요청이 대기 중 |
| `400` | `work_session_extend_not_later`, `work_session_extension_reason_required`, `work_session_extension_already_pending` | 잘못된 연장 요청 또는 다른 연장 요청이 대기 중 |
| `400` | `work_session_invalid_recommendation_item`, `work_session_sudo_loosen_forbidden` | 잘못된 승인 조정 사항 |
| `400` | `approval_request_already_reviewed_or_cancelled` | 승인이 이미 결정되었거나 취소됨 |
| `400` | `auth_mfa_required` | 승인 또는 거부에 새로운 MFA 인증 필요. `source` 필드 없음 |
| `400` | `work_session_not_assignee` | 배정된 사용자만 권고 사항을 확인할 수 있음 |
| `400` | `work_session_ai_unavailable` | scope 추천 사용 불가 |
| `400` | `invalid_input`, `api_invalid_cursor`, `api_cursor_expired` | 잘못된 쿼리, 녹화 세션 또는 커서 |
| `400` | `user_not_found` | 대기 중인 수정 요청의 요청자를 찾을 수 없음 |
| `401` | `auth_token_missing` | 인증 정보 없음 |
| `402` | `workspace_plan_update_required` | 유료 기능, 감사 기록 조회 기간 또는 Free 요금제의 배정 제한 |
| `403` | `api_token_scope_missing` | 토큰 scope 부족. `gate: "token_scope"` 포함 |
| `403` | `permission_denied` | 세션 권한 부족 또는 허용되지 않은 승인 채널 |
| `403` | `approval_request_not_approver`, `approval_requester_may_not_approve`, `approval_no_other_approver` | 승인 권한 또는 승인 가능한 사용자 조건 미충족 |
| `403` | `work_session_agent_not_allowed` | 선언한 에이전트가 허용되지 않음 |
| `403` | `work_session_sudo_bypass_console_only`, `sudo_policy_bypass_agent_session_needs_presence` | 세션 승인이 sudo MFA를 대신하는 정책 요청에는 콘솔 또는 사용자 인증 필요 |
| `403` | `workspace_suspended` | 정지된 워크스페이스에 쓰기 요청. 승인과 거부는 예외 |
| `404` | `api_not_found` | 세션 또는 녹화 기록 조회 불가 |
| `405` | 지원하지 않는 메서드 | 작업 세션 삭제는 지원하지 않음 |
| `503` | `api_search_unavailable` | 녹화 기록 검색 사용 불가 |

인증과 오류 응답 형식은 [API 참조](/reference/api/)를 참고하세요.

Source: https://docs.alpacax.com/ko/reference/api/work-sessions/
