<a id="api-system"></a>
# 인증·대화·정책·운영 API 전수 참조

auth, health, settings, update, logs, chat, side-question와 notification 영역의 등록 operation을 전수 색인한다. 이 페이지는 route/address/auth/handler 요약이고 field-level 계약은 [API 의미 schema](schema-reference.md#api-schema-reference)가 소유한다.

> **분모** · 이 페이지 68개 / 전체 261개. route 등록·auth·직접 handler는 C다. 요청/응답 semantic은 operation별 C/P/U를 분리하며 route 수를 semantic 완료율로 쓰지 않는다.

## Operation 색인

| operation | handler | auth | 입력 | status | schema |
|---|---|---|---|---|---|
| [`GET /api/auth/status`](#op-get-api-auth-status) | `authStatus` | 공개(middleware 면제) | none | `200/503` | [P](schema-reference.md#schema-get-api-auth-status) |
| [`POST /api/auth/init`](#op-post-api-auth-init) | `authInit` | 공개(middleware 면제) | JSON | `200/400/403/500/503` | [P](schema-reference.md#schema-post-api-auth-init) |
| [`POST /api/auth/login`](#op-post-api-auth-login) | `authLogin` | 공개(middleware 면제) | JSON | `200/400/401/403/500/503` | [P](schema-reference.md#schema-post-api-auth-login) |
| [`POST /api/auth/change-password`](#op-post-api-auth-change-password) | `authChangePassword` | 공통 middleware 면제; handler가 Bearer→cookie→query `token` JWT와 현재 암호 재검증 | JSON | `200/400/401/403/500/503` | [C](schema-reference.md#schema-post-api-auth-change-password) |
| [`GET /api/health`](#op-get-api-health) | `health` | 공개(middleware 면제) | none | `200` | [P](schema-reference.md#schema-get-api-health) |
| [`GET /api/stats`](#op-get-api-stats) | `stats` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query task | `200/401/404` | [P](schema-reference.md#schema-get-api-stats) |
| [`GET /api/logs`](#op-get-api-logs) | `getLogs` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query limit,since | `200/401` | [P](schema-reference.md#schema-get-api-logs) |
| [`GET /api/logs/history`](#op-get-api-logs-history) | `getLogsHistory` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query before,limit | `200/401/500` | [P](schema-reference.md#schema-get-api-logs-history) |
| [`GET /api/logs/stream`](#op-get-api-logs-stream) | `streamLogs` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query since | `200/401/500` | [P](schema-reference.md#schema-get-api-logs-stream) |
| [`GET /api/update/check`](#op-get-api-update-check) | `updateCheck` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query force | `200/401` | [P](schema-reference.md#schema-get-api-update-check) |
| [`POST /api/update/apply`](#op-post-api-update-apply) | `updateApply` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `202/400/401/409/502` | [P](schema-reference.md#schema-post-api-update-apply) |
| [`POST /api/update/rollback`](#op-post-api-update-rollback) | `updateRollback` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `202/400/401/409` | [C](schema-reference.md#schema-post-api-update-rollback) |
| [`GET /api/update/stream`](#op-get-api-update-stream) | `updateStream` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500` | [P](schema-reference.md#schema-get-api-update-stream) |
| [`GET /api/workspace/list`](#op-get-api-workspace-list) | `wsList` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query path | `200/400/401/404/500` | [P](schema-reference.md#schema-get-api-workspace-list) |
| [`GET /api/workspace/read`](#op-get-api-workspace-read) | `wsRead` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query path | `200/400/401/404/500` | [P](schema-reference.md#schema-get-api-workspace-read) |
| [`POST /api/workspace/write`](#op-post-api-workspace-write) | `wsWrite` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500` | [P](schema-reference.md#schema-post-api-workspace-write) |
| [`POST /api/workspace/mkdir`](#op-post-api-workspace-mkdir) | `wsMkdir` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500` | [P](schema-reference.md#schema-post-api-workspace-mkdir) |
| [`DELETE /api/workspace/delete`](#op-delete-api-workspace-delete) | `wsDelete` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query path | `200/400/401/404/500` | [C](schema-reference.md#schema-delete-api-workspace-delete) |
| [`GET /api/workspace/download`](#op-get-api-workspace-download) | `wsDownload` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query path | `200/206/304/400/401/404/412/416` | [P](schema-reference.md#schema-get-api-workspace-download) |
| [`POST /api/workspace/upload`](#op-post-api-workspace-upload) | `wsUpload` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query path; multipart/form-data | `200/400/401/500` | [P](schema-reference.md#schema-post-api-workspace-upload) |
| [`GET /api/tokens/daily`](#op-get-api-tokens-daily) | `tokenDailyStats` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query days | `200/401/500` | [P](schema-reference.md#schema-get-api-tokens-daily) |
| [`GET /api/tokens/conversations`](#op-get-api-tokens-conversations) | `conversationTokens` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500` | [P](schema-reference.md#schema-get-api-tokens-conversations) |
| [`GET /api/tokens/usage`](#op-get-api-tokens-usage) | `pgUsageStats` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query days | `200/401/500` | [P](schema-reference.md#schema-get-api-tokens-usage) |
| [`GET /api/audit`](#op-get-api-audit) | `getAudit` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query task | `200/401` | [P](schema-reference.md#schema-get-api-audit) |
| [`POST /api/gc`](#op-post-api-gc) | `gc` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401` | [C](schema-reference.md#schema-post-api-gc) |
| [`GET /api/commands`](#op-get-api-commands) | `pgListCommands` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query page,q,size,task | `200/401/500` | [P](schema-reference.md#schema-get-api-commands) |
| [`GET /api/commands/stats`](#op-get-api-commands-stats) | `pgToolStats` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query q,task | `200/401/500` | [P](schema-reference.md#schema-get-api-commands-stats) |
| [`GET /api/settings`](#op-get-api-settings) | `getSettings` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401` | [P](schema-reference.md#schema-get-api-settings) |
| [`PUT /api/settings`](#op-put-api-settings) | `putSettings` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500` | [P](schema-reference.md#schema-put-api-settings) |
| [`GET /api/notify/meta`](#op-get-api-notify-meta) | `notifyMeta` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500/503` | [P](schema-reference.md#schema-get-api-notify-meta) |
| [`GET /api/notify/channels`](#op-get-api-notify-channels) | `notifyListChannels` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500/503` | [P](schema-reference.md#schema-get-api-notify-channels) |
| [`POST /api/notify/channels`](#op-post-api-notify-channels) | `notifyCreateChannel` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500/503` | [P](schema-reference.md#schema-post-api-notify-channels) |
| [`PATCH /api/notify/channels/{id}`](#op-patch-api-notify-channels-id) | `notifyUpdateChannel` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; JSON | `200/400/401/404/500/503` | [P](schema-reference.md#schema-patch-api-notify-channels-id) |
| [`DELETE /api/notify/channels/{id}`](#op-delete-api-notify-channels-id) | `notifyDeleteChannel` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/404/500/503` | [C](schema-reference.md#schema-delete-api-notify-channels-id) |
| [`POST /api/notify/channels/{id}/test`](#op-post-api-notify-channels-id-test) | `notifyTestChannel` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/404/500/502/503` | [P](schema-reference.md#schema-post-api-notify-channels-id-test) |
| [`GET /api/notify/deliveries`](#op-get-api-notify-deliveries) | `notifyListDeliveries` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query channel_id,event_kind,page,page_size,state | `200/401/500/503` | [P](schema-reference.md#schema-get-api-notify-deliveries) |
| [`POST /api/notify/deliveries/{id}/retry`](#op-post-api-notify-deliveries-id-retry) | `notifyRetryDelivery` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/503` | [C](schema-reference.md#schema-post-api-notify-deliveries-id-retry) |
| [`POST /api/settings/web-search/test`](#op-post-api-settings-web-search-test) | `testWebSearch` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401` | [P](schema-reference.md#schema-post-api-settings-web-search-test) |
| [`PATCH /api/triggers/{id}`](#op-patch-api-triggers-id) | `pgUpdateTrigger` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; JSON | `200/400/401/500/503` | [C](schema-reference.md#schema-patch-api-triggers-id) |
| [`DELETE /api/triggers/{id}`](#op-delete-api-triggers-id) | `pgDeleteTrigger` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/500/503` | [P](schema-reference.md#schema-delete-api-triggers-id) |
| [`POST /api/settings/python/detect`](#op-post-api-settings-python-detect) | `pgDetectPython` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/404/500` | [P](schema-reference.md#schema-post-api-settings-python-detect) |
| [`GET /api/sync/scopesentry/status`](#op-get-api-sync-scopesentry-status) | `syncSSStatus` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500/503` | [P](schema-reference.md#schema-get-api-sync-scopesentry-status) |
| [`POST /api/sync/scopesentry/datasource`](#op-post-api-sync-scopesentry-datasource) | `syncSSDatasource` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/401/500/503` | [P](schema-reference.md#schema-post-api-sync-scopesentry-datasource) |
| [`GET /api/sync/scopesentry/projects`](#op-get-api-sync-scopesentry-projects) | `syncSSProjects` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query page,search,size | `200/401/502/503` | [P](schema-reference.md#schema-get-api-sync-scopesentry-projects) |
| [`GET /api/sync/scopesentry/tasks`](#op-get-api-sync-scopesentry-tasks) | `syncSSTasks` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query page,search,size | `200/401/502/503` | [P](schema-reference.md#schema-get-api-sync-scopesentry-tasks) |
| [`POST /api/sync/scopesentry/sync`](#op-post-api-sync-scopesentry-sync) | `syncSSRun` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/502/503` | [P](schema-reference.md#schema-post-api-sync-scopesentry-sync) |
| [`GET /api/intercept/rules`](#op-get-api-intercept-rules) | `interceptListRules` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500/503` | [P](schema-reference.md#schema-get-api-intercept-rules) |
| [`POST /api/intercept/rules`](#op-post-api-intercept-rules) | `interceptCreateRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500/503` | [P](schema-reference.md#schema-post-api-intercept-rules) |
| [`PUT /api/intercept/rules/{id}`](#op-put-api-intercept-rules-id) | `interceptUpdateRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; JSON | `200/400/401/500/503` | [P](schema-reference.md#schema-put-api-intercept-rules-id) |
| [`DELETE /api/intercept/rules/{id}`](#op-delete-api-intercept-rules-id) | `interceptDeleteRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/500/503` | [P](schema-reference.md#schema-delete-api-intercept-rules-id) |
| [`POST /api/intercept/rules/{id}/toggle`](#op-post-api-intercept-rules-id-toggle) | `interceptToggleRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; JSON | `200/400/401/500/503` | [P](schema-reference.md#schema-post-api-intercept-rules-id-toggle) |
| [`GET /api/asset-intercept/rules`](#op-get-api-asset-intercept-rules) | `assetInterceptListRules` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500/503` | [P](schema-reference.md#schema-get-api-asset-intercept-rules) |
| [`POST /api/asset-intercept/rules`](#op-post-api-asset-intercept-rules) | `assetInterceptCreateRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500/503` | [P](schema-reference.md#schema-post-api-asset-intercept-rules) |
| [`PUT /api/asset-intercept/rules/{id}`](#op-put-api-asset-intercept-rules-id) | `assetInterceptUpdateRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; JSON | `200/400/401/500/503` | [P](schema-reference.md#schema-put-api-asset-intercept-rules-id) |
| [`DELETE /api/asset-intercept/rules/{id}`](#op-delete-api-asset-intercept-rules-id) | `assetInterceptDeleteRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/500/503` | [P](schema-reference.md#schema-delete-api-asset-intercept-rules-id) |
| [`POST /api/asset-intercept/rules/{id}/toggle`](#op-post-api-asset-intercept-rules-id-toggle) | `assetInterceptToggleRule` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; JSON | `200/400/401/500/503` | [P](schema-reference.md#schema-post-api-asset-intercept-rules-id-toggle) |
| [`GET /api/intercept/pending`](#op-get-api-intercept-pending) | `interceptListPending` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500/503` | [P](schema-reference.md#schema-get-api-intercept-pending) |
| [`GET /api/intercept/pending/{id}`](#op-get-api-intercept-pending-id) | `interceptGetOne` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/404/500/503` | [P](schema-reference.md#schema-get-api-intercept-pending-id) |
| [`POST /api/intercept/pending/{id}/decide`](#op-post-api-intercept-pending-id-decide) | `interceptDecide` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; JSON | `200/400/401/409/500` | [C](schema-reference.md#schema-post-api-intercept-pending-id-decide) |
| [`GET /api/intercept/history`](#op-get-api-intercept-history) | `interceptHistory` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query decision_source,page,size,status | `200/400/401/500/503` | [P](schema-reference.md#schema-get-api-intercept-history) |
| [`GET /api/intercept/history/{id}`](#op-get-api-intercept-history-id) | `interceptDetail` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id | `200/400/401/404/500/503` | [P](schema-reference.md#schema-get-api-intercept-history-id) |
| [`GET /api/intercept/history/{id}/execution`](#op-get-api-intercept-history-id-execution) | `interceptExecution` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path id; query conversation | `200/400/401/404/409/410/500/503` | [P](schema-reference.md#schema-get-api-intercept-history-id-execution) |
| [`GET /api/intercept/task/{taskID}`](#op-get-api-intercept-task-taskid) | `interceptListTaskItems` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | path taskID; query decision_source,page,size,status | `200/400/401/500/503` | [P](schema-reference.md#schema-get-api-intercept-task-taskid) |
| [`GET /api/intercept/tool-config`](#op-get-api-intercept-tool-config) | `interceptGetToolConfig` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401/500` | [P](schema-reference.md#schema-get-api-intercept-tool-config) |
| [`PUT /api/intercept/tool-config`](#op-put-api-intercept-tool-config) | `interceptSetToolConfig` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500` | [C](schema-reference.md#schema-put-api-intercept-tool-config) |
| [`GET /api/intercept/judge`](#op-get-api-intercept-judge) | `interceptGetJudgeConfig` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | none | `200/401` | [P](schema-reference.md#schema-get-api-intercept-judge) |
| [`PUT /api/intercept/judge`](#op-put-api-intercept-judge) | `interceptSetJudgeConfig` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | JSON | `200/400/401/500` | [C](schema-reference.md#schema-put-api-intercept-judge) |
| [`GET /api/intercept/judge/usage`](#op-get-api-intercept-judge-usage) | `interceptJudgeUsage` | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 | query days | `200/401/500` | [P](schema-reference.md#schema-get-api-intercept-judge-usage) |

<a id="op-get-api-auth-status"></a>
## `GET /api/auth/status`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `authStatus` · `server/auth.go` · [handler 근거](evidence:handler-get-api-auth-status) |
| 인증 | 공개(middleware 면제) |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-auth-status) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-auth-init"></a>
## `POST /api/auth/init`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `authInit` · `server/auth.go` · [handler 근거](evidence:handler-post-api-auth-init) |
| 인증 | 공개(middleware 면제) |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 403, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-auth-init) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-post-api-auth-login"></a>
## `POST /api/auth/login`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `authLogin` · `server/auth.go` · [handler 근거](evidence:handler-post-api-auth-login) |
| 인증 | 공개(middleware 면제) |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 403, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-auth-login) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-post-api-auth-change-password"></a>
## `POST /api/auth/change-password`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `authChangePassword` · `server/auth.go` · [handler 근거](evidence:handler-post-api-auth-change-password) |
| 인증 | 공통 middleware 면제; handler가 Bearer→cookie→query `token` JWT와 현재 암호 재검증 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 403, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-post-api-auth-change-password) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-health"></a>
## `GET /api/health`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `health` · `server/server.go` · [handler 근거](evidence:handler-get-api-health) |
| 인증 | 공개(middleware 면제) |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-health) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-stats"></a>
## `GET /api/stats`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `stats` · `server/server.go` · [handler 근거](evidence:handler-get-api-stats) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `task` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 404` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-stats) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-logs"></a>
## `GET /api/logs`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `getLogs` · `server/server.go` · [handler 근거](evidence:handler-get-api-logs) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `limit, since` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-logs) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-logs-history"></a>
## `GET /api/logs/history`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `getLogsHistory` · `server/server.go` · [handler 근거](evidence:handler-get-api-logs-history) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `before, limit` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-logs-history) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-logs-stream"></a>
## `GET /api/logs/stream`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `streamLogs` · `server/server.go` · [handler 근거](evidence:handler-get-api-logs-stream) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `since` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-logs-stream) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · SSE 연결 수립; event lifecycle은 stream별 cursor/메모리 상태를 확인 |

<a id="op-get-api-update-check"></a>
## `GET /api/update/check`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `updateCheck` · `server/update.go` · [handler 근거](evidence:handler-get-api-update-check) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `force` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-update-check) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-update-apply"></a>
## `POST /api/update/apply`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `updateApply` · `server/update.go` · [handler 근거](evidence:handler-post-api-update-apply) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `202, 400, 401, 409, 502` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-update-apply) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · download/apply worker 시작 후 process restart; 새 health/version이 완료 기준 |

<a id="op-post-api-update-rollback"></a>
## `POST /api/update/rollback`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `updateRollback` · `server/update.go` · [handler 근거](evidence:handler-post-api-update-rollback) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `202, 400, 401, 409` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-post-api-update-rollback) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · rollback stage 후 restart 요청; 재기동 version이 완료 기준 |

<a id="op-get-api-update-stream"></a>
## `GET /api/update/stream`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `updateStream` · `server/update.go` · [handler 근거](evidence:handler-get-api-update-stream) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-update-stream) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · SSE 연결 수립; event lifecycle은 stream별 cursor/메모리 상태를 확인 |

<a id="op-get-api-workspace-list"></a>
## `GET /api/workspace/list`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `wsList` · `server/workspace.go` · [handler 근거](evidence:handler-get-api-workspace-list) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `path` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-workspace-list) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-workspace-read"></a>
## `GET /api/workspace/read`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `wsRead` · `server/workspace.go` · [handler 근거](evidence:handler-get-api-workspace-read) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `path` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-workspace-read) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-workspace-write"></a>
## `POST /api/workspace/write`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `wsWrite` · `server/workspace.go` · [handler 근거](evidence:handler-post-api-workspace-write) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-workspace-write) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-post-api-workspace-mkdir"></a>
## `POST /api/workspace/mkdir`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `wsMkdir` · `server/workspace.go` · [handler 근거](evidence:handler-post-api-workspace-mkdir) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-workspace-mkdir) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-delete-api-workspace-delete"></a>
## `DELETE /api/workspace/delete`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `wsDelete` · `server/workspace.go` · [handler 근거](evidence:handler-delete-api-workspace-delete) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `path` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-delete-api-workspace-delete) |
| 반복·완료 | Idempotency-Key/If-Match 없음; 반복 시 응답/존재 검사가 달라질 수 있음 · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-workspace-download"></a>
## `GET /api/workspace/download`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `wsDownload` · `server/workspace.go` · [handler 근거](evidence:handler-get-api-workspace-download) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `path` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 206, 304, 400, 401, 404, 412, 416` · 일반 error body `{error:string}`; helper status는 schema에서 P/U; stdlib `412`는 body 없음, `416`은 `text/plain` |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-workspace-download) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-workspace-upload"></a>
## `POST /api/workspace/upload`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `wsUpload` · `server/workspace.go` · [handler 근거](evidence:handler-post-api-workspace-upload) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `path` · body `multipart/form-data` |
| status/error | 직접 관찰 `200, 400, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-workspace-upload) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-tokens-daily"></a>
## `GET /api/tokens/daily`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `tokenDailyStats` · `server/server.go` · [handler 근거](evidence:handler-get-api-tokens-daily) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `days` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-tokens-daily) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-tokens-conversations"></a>
## `GET /api/tokens/conversations`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `conversationTokens` · `server/server.go` · [handler 근거](evidence:handler-get-api-tokens-conversations) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-tokens-conversations) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-tokens-usage"></a>
## `GET /api/tokens/usage`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `pgUsageStats` · `server/commands.go` · [handler 근거](evidence:handler-get-api-tokens-usage) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `days` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-tokens-usage) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-audit"></a>
## `GET /api/audit`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `getAudit` · `server/server.go` · [handler 근거](evidence:handler-get-api-audit) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `task` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-audit) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-gc"></a>
## `POST /api/gc`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `gc` · `server/server.go` · [handler 근거](evidence:handler-post-api-gc) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-post-api-gc) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-commands"></a>
## `GET /api/commands`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `pgListCommands` · `server/commands.go` · [handler 근거](evidence:handler-get-api-commands) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `page, q, size, task` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-commands) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-commands-stats"></a>
## `GET /api/commands/stats`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `pgToolStats` · `server/commands.go` · [handler 근거](evidence:handler-get-api-commands-stats) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `q, task` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-commands-stats) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-settings"></a>
## `GET /api/settings`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `getSettings` · `server/server.go` · [handler 근거](evidence:handler-get-api-settings) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-settings) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-put-api-settings"></a>
## `PUT /api/settings`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `putSettings` · `server/server.go` · [handler 근거](evidence:handler-put-api-settings) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-put-api-settings) |
| 반복·완료 | Idempotency-Key/If-Match 없음; DB upsert/trigger/side effect 때문에 반복 의미를 handler별 확인(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-notify-meta"></a>
## `GET /api/notify/meta`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyMeta` · `server/notify_api.go` · [handler 근거](evidence:handler-get-api-notify-meta) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-notify-meta) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-notify-channels"></a>
## `GET /api/notify/channels`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyListChannels` · `server/notify_api.go` · [handler 근거](evidence:handler-get-api-notify-channels) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-notify-channels) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-notify-channels"></a>
## `POST /api/notify/channels`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyCreateChannel` · `server/notify_api.go` · [handler 근거](evidence:handler-post-api-notify-channels) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-notify-channels) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · delivery/test effect는 remote channel 결과와 DB delivery state를 함께 확인 |

<a id="op-patch-api-notify-channels-id"></a>
## `PATCH /api/notify/channels/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyUpdateChannel` · `server/notify_api.go` · [handler 근거](evidence:handler-patch-api-notify-channels-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-patch-api-notify-channels-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; DB upsert/trigger/side effect 때문에 반복 의미를 handler별 확인(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-delete-api-notify-channels-id"></a>
## `DELETE /api/notify/channels/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyDeleteChannel` · `server/notify_api.go` · [handler 근거](evidence:handler-delete-api-notify-channels-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-delete-api-notify-channels-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; 반복 시 응답/존재 검사가 달라질 수 있음 · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-post-api-notify-channels-id-test"></a>
## `POST /api/notify/channels/{id}/test`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyTestChannel` · `server/notify_api.go` · [handler 근거](evidence:handler-post-api-notify-channels-id-test) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500, 502, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-notify-channels-id-test) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · delivery/test effect는 remote channel 결과와 DB delivery state를 함께 확인 |

<a id="op-get-api-notify-deliveries"></a>
## `GET /api/notify/deliveries`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyListDeliveries` · `server/notify_api.go` · [handler 근거](evidence:handler-get-api-notify-deliveries) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `channel_id, event_kind, page, page_size, state` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-notify-deliveries) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-notify-deliveries-id-retry"></a>
## `POST /api/notify/deliveries/{id}/retry`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `notifyRetryDelivery` · `server/notify_api.go` · [handler 근거](evidence:handler-post-api-notify-deliveries-id-retry) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-post-api-notify-deliveries-id-retry) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · delivery/test effect는 remote channel 결과와 DB delivery state를 함께 확인 |

<a id="op-post-api-settings-web-search-test"></a>
## `POST /api/settings/web-search/test`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `testWebSearch` · `server/server.go` · [handler 근거](evidence:handler-post-api-settings-web-search-test) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-settings-web-search-test) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-patch-api-triggers-id"></a>
## `PATCH /api/triggers/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `pgUpdateTrigger` · `server/triggers.go` · [handler 근거](evidence:handler-patch-api-triggers-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-patch-api-triggers-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; DB upsert/trigger/side effect 때문에 반복 의미를 handler별 확인(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-delete-api-triggers-id"></a>
## `DELETE /api/triggers/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `pgDeleteTrigger` · `server/triggers.go` · [handler 근거](evidence:handler-delete-api-triggers-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-delete-api-triggers-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; 반복 시 응답/존재 검사가 달라질 수 있음 · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-post-api-settings-python-detect"></a>
## `POST /api/settings/python/detect`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `pgDetectPython` · `server/server.go` · [handler 근거](evidence:handler-post-api-settings-python-detect) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 404, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-settings-python-detect) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-sync-scopesentry-status"></a>
## `GET /api/sync/scopesentry/status`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `syncSSStatus` · `server/sync_scopesentry.go` · [handler 근거](evidence:handler-get-api-sync-scopesentry-status) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-sync-scopesentry-status) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-sync-scopesentry-datasource"></a>
## `POST /api/sync/scopesentry/datasource`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `syncSSDatasource` · `server/sync_scopesentry.go` · [handler 근거](evidence:handler-post-api-sync-scopesentry-datasource) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-sync-scopesentry-datasource) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · 외부 ScopeSentry 호출과 local upsert를 수행; HTTP response는 해당 handler run의 결과 |

<a id="op-get-api-sync-scopesentry-projects"></a>
## `GET /api/sync/scopesentry/projects`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `syncSSProjects` · `server/sync_scopesentry.go` · [handler 근거](evidence:handler-get-api-sync-scopesentry-projects) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `page, search, size` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 502, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-sync-scopesentry-projects) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-sync-scopesentry-tasks"></a>
## `GET /api/sync/scopesentry/tasks`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `syncSSTasks` · `server/sync_scopesentry.go` · [handler 근거](evidence:handler-get-api-sync-scopesentry-tasks) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `page, search, size` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 502, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-sync-scopesentry-tasks) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-sync-scopesentry-sync"></a>
## `POST /api/sync/scopesentry/sync`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `syncSSRun` · `server/sync_scopesentry.go` · [handler 근거](evidence:handler-post-api-sync-scopesentry-sync) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 502, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-sync-scopesentry-sync) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · 외부 ScopeSentry 호출과 local upsert를 수행; HTTP response는 해당 handler run의 결과 |

<a id="op-get-api-intercept-rules"></a>
## `GET /api/intercept/rules`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptListRules` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-rules) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-rules) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-intercept-rules"></a>
## `POST /api/intercept/rules`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptCreateRule` · `server/intercept.go` · [handler 근거](evidence:handler-post-api-intercept-rules) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-intercept-rules) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-put-api-intercept-rules-id"></a>
## `PUT /api/intercept/rules/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptUpdateRule` · `server/intercept.go` · [handler 근거](evidence:handler-put-api-intercept-rules-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-put-api-intercept-rules-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; DB upsert/trigger/side effect 때문에 반복 의미를 handler별 확인(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-delete-api-intercept-rules-id"></a>
## `DELETE /api/intercept/rules/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptDeleteRule` · `server/intercept.go` · [handler 근거](evidence:handler-delete-api-intercept-rules-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-delete-api-intercept-rules-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; 반복 시 응답/존재 검사가 달라질 수 있음 · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-post-api-intercept-rules-id-toggle"></a>
## `POST /api/intercept/rules/{id}/toggle`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptToggleRule` · `server/intercept.go` · [handler 근거](evidence:handler-post-api-intercept-rules-id-toggle) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-intercept-rules-id-toggle) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-asset-intercept-rules"></a>
## `GET /api/asset-intercept/rules`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `assetInterceptListRules` · `server/asset_intercept.go` · [handler 근거](evidence:handler-get-api-asset-intercept-rules) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-asset-intercept-rules) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-asset-intercept-rules"></a>
## `POST /api/asset-intercept/rules`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `assetInterceptCreateRule` · `server/asset_intercept.go` · [handler 근거](evidence:handler-post-api-asset-intercept-rules) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-asset-intercept-rules) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-put-api-asset-intercept-rules-id"></a>
## `PUT /api/asset-intercept/rules/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `assetInterceptUpdateRule` · `server/asset_intercept.go` · [handler 근거](evidence:handler-put-api-asset-intercept-rules-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-put-api-asset-intercept-rules-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; DB upsert/trigger/side effect 때문에 반복 의미를 handler별 확인(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-delete-api-asset-intercept-rules-id"></a>
## `DELETE /api/asset-intercept/rules/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `assetInterceptDeleteRule` · `server/asset_intercept.go` · [handler 근거](evidence:handler-delete-api-asset-intercept-rules-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-delete-api-asset-intercept-rules-id) |
| 반복·완료 | Idempotency-Key/If-Match 없음; 반복 시 응답/존재 검사가 달라질 수 있음 · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-post-api-asset-intercept-rules-id-toggle"></a>
## `POST /api/asset-intercept/rules/{id}/toggle`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `assetInterceptToggleRule` · `server/asset_intercept.go` · [handler 근거](evidence:handler-post-api-asset-intercept-rules-id-toggle) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-post-api-asset-intercept-rules-id-toggle) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-intercept-pending"></a>
## `GET /api/intercept/pending`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptListPending` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-pending) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-pending) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-intercept-pending-id"></a>
## `GET /api/intercept/pending/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptGetOne` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-pending-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-pending-id) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-post-api-intercept-pending-id-decide"></a>
## `POST /api/intercept/pending/{id}/decide`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptDecide` · `server/intercept.go` · [handler 근거](evidence:handler-post-api-intercept-pending-id-decide) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 409, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-post-api-intercept-pending-id-decide) |
| 반복·완료 | Idempotency-Key 없음; unique constraint 또는 상태 check가 있는 경우만 중복을 제한(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-intercept-history"></a>
## `GET /api/intercept/history`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptHistory` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-history) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `decision_source, page, size, status` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-history) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-intercept-history-id"></a>
## `GET /api/intercept/history/{id}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptDetail` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-history-id) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-history-id) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-intercept-history-id-execution"></a>
## `GET /api/intercept/history/{id}/execution`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptExecution` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-history-id-execution) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `id` · query `conversation` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 404, 409, 410, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-history-id-execution) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-intercept-task-taskid"></a>
## `GET /api/intercept/task/{taskID}`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptListTaskItems` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-task-taskid) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `taskID` · query `decision_source, page, size, status` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 400, 401, 500, 503` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-task-taskid) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-get-api-intercept-tool-config"></a>
## `GET /api/intercept/tool-config`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptGetToolConfig` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-tool-config) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-tool-config) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-put-api-intercept-tool-config"></a>
## `PUT /api/intercept/tool-config`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptSetToolConfig` · `server/intercept.go` · [handler 근거](evidence:handler-put-api-intercept-tool-config) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-put-api-intercept-tool-config) |
| 반복·완료 | Idempotency-Key/If-Match 없음; DB upsert/trigger/side effect 때문에 반복 의미를 handler별 확인(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-intercept-judge"></a>
## `GET /api/intercept/judge`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptGetJudgeConfig` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-judge) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-judge) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="op-put-api-intercept-judge"></a>
## `PUT /api/intercept/judge`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptSetJudgeConfig` · `server/intercept.go` · [handler 근거](evidence:handler-put-api-intercept-judge) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `-` · body `JSON` |
| status/error | 직접 관찰 `200, 400, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [C: 직접 scalar/static top-level key와 field type을 추출; nested 내부 schema는 별도 type 참조가 없으면 P](schema-reference.md#schema-put-api-intercept-judge) |
| 반복·완료 | Idempotency-Key/If-Match 없음; DB upsert/trigger/side effect 때문에 반복 의미를 handler별 확인(P) · handler의 직접 mutation/호출 후 응답; 외부 전달·agent 실행이 파생되면 별도 상태 확인(P) |

<a id="op-get-api-intercept-judge-usage"></a>
## `GET /api/intercept/judge/usage`

| 계약 | 확인 결과 |
|---|---|
| 등록·handler | `interceptJudgeUsage` · `server/intercept.go` · [handler 근거](evidence:handler-get-api-intercept-judge-usage) |
| 인증 | JWT 필요; `extractToken`이 Bearer→cookie→query `token` 순으로 선택 |
| wire 입력 | path `-` · query `days` · body `없음(직접 body decode 미발견)` |
| status/error | 직접 관찰 `200, 401, 500` · 일반 error body `{error:string}`; helper status는 schema에서 P/U |
| 응답·validation | [P: top-level key는 직접 추출했지만 derived/helper/opaque 또는 nested type이 남음](schema-reference.md#schema-get-api-intercept-judge-usage) |
| 반복·완료 | read/stream 요청; stream 재연결은 cursor 계약에 따름 · 직접 조회/파일 전송 완료; 외부 조회가 있으면 응답 전 handler 결과만 보장 |

<a id="api-page-limit"></a>
## 이 페이지의 확인 한계

- route registration/auth/handler 직접 목적지는 전수 확인했다.
- field/schema/error/side-effect 의미는 별도 schema page의 C/P/U가 권위다.
- OpenAPI가 없고 실제 HTTP server는 실행하지 않았다. helper 내부·외부 서비스·DB 운영 상태는 정적 소스 이상으로 보장하지 않는다.
