# REST로 업무 시키기

> **이 장에서 배우는 것**
> `/api/v1`로 업무를 만들고 지켜보고 멈추는 법, 그리고 자동화에 붙일 때 반드시
> 처리해야 할 것 하나.
>
> **요청·응답·상태 코드가 낯설다면** [요청과 응답 — HTTP](/guide/it-http)를 먼저 보세요.

## 화면에서 하던 것을 코드로

[첫 업무 맡기기](/guide/ht-first-task)에서 화면으로 했던 것을 그대로 REST로
합니다. **같은 함수를 부릅니다** — 화면에서 만든 업무와 API로 만든 업무는 구분이
없습니다.

## 다섯 개의 엔드포인트

| 하는 일 | 요청 |
|---|---|
| 작업 폴더 목록 | `GET /api/v1/workspaces` |
| 업무 목록 | `GET /api/v1/tasks` |
| **업무 만들기** | `POST /api/v1/tasks` |
| 업무 하나 보기 | `GET /api/v1/tasks/{id}` |
| 이어 말하기 | `POST /api/v1/tasks/{id}/follow-up` |
| 중지 | `POST /api/v1/tasks/{id}/stop` |

## 업무 만들기

```bash
curl -X POST http://localhost:27777/api/v1/tasks \
  -H "Authorization: Bearer $HT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workspaceId": 3,
    "prompt": "이 폴더의 테스트 없는 파일 목록을 뽑아 표로 정리해줘",
    "name": "테스트 커버리지 점검"
  }'
```

### 넣을 수 있는 것

| 필드 | 뜻 | 안 넣으면 |
|---|---|---|
| `workspaceId` | 어느 작업 폴더에서 | 필수에 가까움 |
| `prompt` | 지시 내용 | 빈 업무가 됨 |
| `name` | 목록에 표시될 이름 | 자동 생성 |
| `engine` | 어느 엔진으로 | 기본 엔진 |
| `mode` | 자율성 수준 | **전부 자동** |
| `model` | 어느 모델로 | 기본 모델 |

> **`mode`를 빼면 [전부 자동](/guide/ht-autonomy)입니다.** 화면에서와 같은
> 기본값입니다. 사람이 안 보는 자동화라면 이게 무슨 뜻인지 알고 넣어야 합니다.

### 작업 폴더 번호는 어디서 얻나

```bash
curl -H "Authorization: Bearer $HT_KEY" \
  http://localhost:27777/api/v1/workspaces
```

경로와 함께 번호가 돌아옵니다. **번호를 하드코딩하지 말고 경로로 찾으세요** —
폴더를 지웠다 다시 등록하면 번호가 바뀝니다.

## 멱등 키가 없습니다

이 장에서 가장 중요한 부분입니다.

> **같은 요청을 두 번 보내면 업무가 두 개 생깁니다.**

이건 빠뜨린 게 아니라 **의도한 설계**입니다. 코드 주석이 그 이유를 이렇게
적어두었습니다 — *"REST 호출자는 자기 요청을 한 번만 보내면 됩니다. 없는 보장을
있는 척하지 않습니다."*

### 그래서 자동화에서 무슨 일이 생기나

```mermaid
graph TD
  A["스크립트가 POST"] --> B{"응답이 왔나?"}
  B -->|"왔음"| C["정상"]
  B -->|"타임아웃"| D["재시도?"]
  D -->|"그냥 재시도"| E["업무 2개 생성<br/>둘 다 파일을 고침"]
  D -->|"먼저 조회"| F["안전"]
```

**타임아웃이 곧 실패는 아닙니다.** 요청은 도착했는데 응답만 못 받았을 수
있습니다. 그 상태에서 재시도하면 같은 일이 두 번 실행됩니다.

### 처리 방법

```
□ 재시도 전에 GET /api/v1/tasks 로 최근 목록을 확인
□ name 에 고유한 값을 넣어 중복을 알아볼 수 있게
□ 재시도 횟수에 상한 (무한 재시도 금지)
□ 파일을 고치는 업무라면 재시도를 아예 사람 확인으로
```

**`name`을 활용하는 게 가장 실용적입니다.**

```json
{ "name": "일일점검-2026-08-15" }
```

날짜나 실행 식별자를 이름에 넣어두면, 재시도 전에 목록을 훑어 **이미 있는지
확인**할 수 있습니다.

![사용량 탭에서 이 컴퓨터가 무엇에 얼마나](/guide-assets/ht-usage.png)

사용량 탭에서 이 컴퓨터가 무엇에 얼마나 썼는지 확인합니다.

## 진행 상황 보기

업무를 만들면 식별자가 돌아옵니다. 그걸로 조회합니다.

```bash
curl -H "Authorization: Bearer $HT_KEY" \
  http://localhost:27777/api/v1/tasks/42
```

오래 걸리는 업무는 **폴링 간격을 넉넉히** 잡으세요. 1초마다 찌르는 것은 얻는 게
없습니다.

| 상황 | 간격 |
|---|---|
| 몇 초짜리 | 2~3초 |
| 몇 분짜리 | 15~30초 |
| 몇 시간짜리 | 몇 분 |

## 이어 말하기와 중지

```bash
# 결과가 아쉬울 때 — 화면에서 이어 말하는 것과 같음
curl -X POST http://localhost:27777/api/v1/tasks/42/follow-up \
  -H "Authorization: Bearer $HT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "표에 마지막 수정일 열을 추가해줘" }'

# 잘못 가고 있을 때
curl -X POST http://localhost:27777/api/v1/tasks/42/stop \
  -H "Authorization: Bearer $HT_KEY"
```

**`stop`은 자동화에 반드시 넣으세요.** [에이전트는 틀린 방향으로도 열심히
갑니다](/guide/ai-agent-basics). 사람이 안 보는 자동화에서는 시간이나 비용 상한을
넘으면 스스로 멈추게 해야 합니다.

## 어디에 쓰나

| 상황 | 형태 |
|---|---|
| 사내 포털에 버튼 하나 | 버튼 → POST → 결과를 화면에 |
| 이슈 트래커 연동 | 이슈 생성 → 업무 자동 생성 |
| 정기 배치 | 스케줄러 → POST → 결과를 메일로 |
| 챗봇 | 메시지 → 업무 → 답변 회신 |

> **정기 실행이라면 이 API 대신 [예약](/guide/ht-pipelines)이 낫습니다.** 바깥에
> 스케줄러를 두는 것보다 시스템 안의 예약이 관리하기 쉽습니다. API는 **바깥의
> 사건이 방아쇠일 때** 쓰세요.

## 안전하게 붙이기

```
□ 처음에는 mode 를 "계획만" 으로 고정하고 결과를 사람이 확인
□ 익숙해지면 되돌릴 수 있는 범위까지 자율성을 올림
□ workspaceId 를 코드에 하드코딩하지 말고 경로로 조회
□ 열쇠는 환경변수. 코드·저장소·로그에 남기지 않기
□ 자동화 초기 며칠은 만들어진 업무를 눈으로 확인
```

**첫 줄이 특히 중요합니다.** 자동화가 파일을 고치기 시작하면 되돌리기 어렵고,
[git 커밋](/guide/ht-autonomy) 없이는 확인도 어렵습니다.

---

## 확인

**1. 같은 POST를 두 번 보내면 어떻게 됩니까?**

<details>
<summary>답</summary>

**업무가 두 개 생깁니다.** 멱등 키가 없는 것이 의도된 설계이므로, 재시도를
넣는 쪽이 중복을 책임져야 합니다 — 재시도 전에 목록을 조회하거나 `name`에 고유
값을 넣어 확인합니다.
</details>

**2. `mode`를 안 넣으면 어떤 자율성으로 실행됩니까?**

<details>
<summary>답</summary>

**전부 자동**입니다. 화면에서와 같은 기본값이라, 사람이 안 보는 자동화라면 이게
무슨 뜻인지 알고 넣어야 합니다.
</details>

**3. 정기 실행에 이 API를 쓰는 게 왜 차선입니까?**

<details>
<summary>답</summary>

**바깥에 스케줄러를 따로 둬야 하기 때문**입니다. 시스템 안의 예약이 관리하기
쉽습니다. API는 바깥의 사건이 방아쇠일 때 쓰는 게 맞습니다.
</details>

---

직접 걸어보고 중복 실행까지 만들어봅니다. 40분입니다 →
[REST로 업무를 걸어보기](/guide/ht-try-rest)
