완전한 REST 엔드포인트 레퍼런스. 튜토리얼과 예제는 API 가이드를 참고하세요.
프로젝트 멤버가 웹 UI에서 할 수 있는 모든 것을 여기서 사용할 수 있습니다 — SPA는 이 동일한 API를 사용합니다. owner 역할을 요구하는 작업은 (owner)로 표시됩니다. 그 외 모든 것은 프로젝트 멤버십만 필요합니다(또는 (viewer)로 표시된 읽기의 경우 모든 접근 수준).
https://eastagiletracker.com/api/v1https://api.eastagiletracker.com/api/v1도 동일한 API를 제공합니다. multipart를 받는 몇몇 파일 업로드 엔드포인트를 제외하고, 모든 요청과 응답은 JSON입니다.
모든 인증된 요청은 다음 중 하나로 API 키를 보냅니다:
X-TrackerToken: <key>Authorization: Bearer <key>
User key는 ea_user_로 시작합니다. Agent key는 ea_agent_로 시작합니다. API 가이드 → 두 종류의 키를 참고하세요.
인증되지 않은 엔드포인트: /openapi.json, /docs, /auth/* 엔드포인트, 그리고 참조 데이터 조회(/story_types, /story_states, /effort_scales, …). /meta는 인증됨입니다 — 유효한 키라면 작동하지만 프로젝트 범위가 아닙니다(프로젝트에 묶인 에이전트 키도 도달합니다).
세 수준이 프로젝트 범위 엔드포인트를 통제합니다:
| Level | Who passes | Typical operations |
|---|---|---|
| viewer | viewer, member, owner | 읽기(스토리 목록/조회, 검색, 분석) |
| member | member, owner | 모든 작업 항목 쓰기(스토리, 작업, 댓글, …) |
| owner | owner only | 프로젝트 설정, 멤버십 관리, 에이전트 키, 삭제, 임포트, 감사 로그 |
비멤버는 프로젝트 경로에서 403이 아니라 404 unfound_resource를 받으므로, 프로젝트 ID를 열거할 수 없습니다.
자기 기술 엔드포인트
섹션 제목: “자기 기술 엔드포인트”| Method | Path | Description |
|---|---|---|
| GET | /openapi.json | 실시간 OpenAPI 3 스펙. 인증되지 않음. |
| GET | /docs | Swagger UI. 인증되지 않음. |
| GET | /meta | 호출자 정체성(auth.kind/key_id/agent_id/project_id) + 스토리 유형 전환 그래프. 인증됨(유효한 키라면; 프로젝트 범위 아님). 이것을 먼저 호출하세요. |
계정 / 정체성
섹션 제목: “계정 / 정체성”이것들은 호출자에 대해 작동하며 유효한 키만 필요합니다(프로젝트 역할 없음).
| Method | Path | Description |
|---|---|---|
| POST | /auth/register | 새 계정 등록 |
| POST | /auth/login | 로그인, 세션 토큰 반환 |
| POST | /auth/logout | 로그아웃 |
| POST | /auth/forgot-password | 비밀번호 재설정 이메일 요청 |
| POST | /auth/reset-password | 재설정 토큰으로 새 비밀번호 설정 |
| GET | /auth/verify-email | 이메일 주소 인증 |
| POST | /auth/accept-invite/lookup | 초대 토큰 → 이메일 해석(인증되지 않음) |
| POST | /auth/accept-invite | 프로젝트 초대 수락(인증 후) |
| GET | /me | 현재 사용자 프로필 |
| PUT | /me | 프로필 업데이트 |
| DELETE | /me | 계정 삭제 |
| PUT | /me/password | 비밀번호 변경 |
| PUT | /me/settings | 설정 업데이트(테마, 알림 환경 설정) |
| POST | /me/avatar | 아바타 업로드(multipart) |
| POST | /me/api-token/regenerate | API 토큰 회전 — 기존 세션/키 무효화 |
| GET | /me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id} | 사용자(ea_user_) API 키 관리 |
| GET | /me/activity | 모든 프로젝트에 걸친 여러분의 활동 |
| GET | /me/data-export | 여러분 데이터의 GDPR 자체 익스포트 |
| GET | /me/consent · POST /me/consent | 동의 읽기 / 기록({ consent_type, granted }) |
| GET | /legal/pending · POST /legal/accept | 대기 중인 클릭랩 문서 / 수락 기록 |
| POST | /contact · POST /feedback · POST /feedback/with-screenshot | 문의 + 앱 내 피드백 |
참조 데이터(인증되지 않음)
섹션 제목: “참조 데이터(인증되지 않음)”스토리를 생성/추정할 때 사용되는 시드 조회. 안정적인 ID.
| Method | Path | Description |
|---|---|---|
| GET | /story_types | feature, bug, chore, release (+ allow_points) |
| GET | /story_states | unstarted … accepted, rejected |
| GET | /effort_scales | 사용 가능한 추정 척도 |
| GET | /effort_scales/{scale_id}/values | 척도의 포인트 값 |
프로젝트
섹션 제목: “프로젝트”| Method | Path | Description |
|---|---|---|
| GET | /projects | 여러분의 프로젝트 목록 |
| POST | /projects | 프로젝트 생성 |
| GET | /projects/{id} | 프로젝트 상세 조회 (viewer) |
| PUT | /projects/{id} | 프로젝트 설정 업데이트 (owner) |
| DELETE | /projects/{id} | 프로젝트 삭제 (owner) |
| GET | /projects/{id}/audit-log | 프로젝트 활동 스트림 (owner) |
| GET | /projects/{id}/events | 커서 페이지네이션 이벤트 스트림 (viewer) — Events 참고 |
멤버와 에이전트 키
섹션 제목: “멤버와 에이전트 키”| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/memberships | 멤버 목록 (viewer) |
| POST | /projects/{id}/memberships | 이메일로 멤버 초대 (owner) |
| PUT | /projects/{id}/memberships/{mid} | 역할 업데이트 (owner) |
| DELETE | /projects/{id}/memberships/{mid} | 멤버 제거 (owner) |
| GET / POST | /projects/{id}/agent_keys | 에이전트 키 목록 / 발급 (owner) |
| DELETE | /projects/{id}/agent_keys/{kid} | 에이전트 키 취소 (owner) |
스토리
섹션 제목: “스토리”모든 스토리 쓰기는 member 역할이 필요합니다.
| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/stories | 스토리 목록(페이지네이션, 필터 가능) (viewer) |
| POST | /projects/{id}/stories | 스토리 생성 |
| GET | /projects/{id}/stories/{sid} | 스토리 하나 조회 (viewer) |
| PUT | /projects/{id}/stories/{sid} | 스토리 업데이트 |
| DELETE | /projects/{id}/stories/{sid} | 스토리 삭제 |
| POST | /projects/{id}/stories/{sid}/transitions | 검증과 함께 상태 변경 |
| POST | /projects/{id}/stories/bulk_transition | 한 번에 많은 스토리(1–100) 전환 |
| POST | /projects/{id}/stories/bulk-delete | 많은 스토리 삭제 |
| POST | /projects/{id}/stories/bulk-duplicate | 많은 스토리 복제 |
| POST | /projects/{id}/stories/{sid}/duplicate | 스토리 하나 복제 |
Create (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. labels는 ["auth"] 또는 [{ "name": "auth" }]를 받으며, 알려지지 않은 라벨은 생성됩니다. 기본값: story_type=feature, current_state=unstarted.
Update (PUT …/stories/{sid}): 동일한 필드, 모두 선택적, 그리고 "position"(float)과 "force_state_change"(bool).
Transition (POST …/transitions): { "to": "<state>", "reason"? }. 필드는 **to**입니다. { story_id, state }를 반환합니다. 불법 이동 → details: { from, to, allowed }와 함께 422 invalid_transition.
Bulk transition (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>", "reason"? }. 각 스토리는 독립적으로 판단됩니다. { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }를 반환합니다.
스토리 하위 리소스
섹션 제목: “스토리 하위 리소스”모두 member. 대부분의 List/GET은 (viewer)입니다.
| Method | Path | Body / notes |
|---|---|---|
| GET / POST | /projects/{id}/stories/{sid}/tasks · PUT/DELETE …/tasks/{tid} | { description (or task_desc), complete?, task_order? } |
| GET / POST | /projects/{id}/stories/{sid}/comments · PUT/DELETE …/comments/{cid} | { text (or comment_text) } or { comment_emoji } |
| GET / POST | /projects/{id}/stories/{sid}/blockers · PUT/DELETE …/blockers/{bid} | { blocker_desc, resolved? } |
| GET / POST | /projects/{id}/stories/{sid}/links · DELETE …/links/{lid} | { url, link_type?, title? } |
| GET / POST | /projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid} | { reviewer_id? / reviewer_agent_id?, status, comment? } |
| GET / POST | /projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid} | { member_id? / agent_id? } — 둘 다 생략하면 호출자를 추가 |
| GET / POST | /projects/{id}/stories/{sid}/followers · DELETE …/followers/{mid} · DELETE …/followers/agents/{aid} | { member_id? / agent_id? } |
| GET / POST | /projects/{id}/stories/{sid}/labels · DELETE …/labels/{lid} | { name } |
| GET / POST | /projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid} | multipart 업로드(각 ≤ 2 GB); 목록은 (viewer) |
쓰기는 member, 읽기는 (viewer).
| Method | Path | Description |
|---|---|---|
| GET / POST | /projects/{id}/labels | 라벨 목록 / 생성 |
| PUT / DELETE | /projects/{id}/labels/{lid} | 라벨 업데이트 / 삭제 |
| POST | /projects/{id}/labels/{lid}/archive | 라벨 보관(소프트 숨김) |
이터레이션
섹션 제목: “이터레이션”| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/iterations | 이터레이션 목록 (member) |
| POST | /projects/{id}/iterations | 수동 이터레이션 생성 (owner) |
| DELETE | /projects/{id}/iterations/{itid} | 이터레이션 삭제 (owner) |
검색, 분석, 지표, 환경 설정
섹션 제목: “검색, 분석, 지표, 환경 설정”| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/search?query=… | 필터 구문 검색 (viewer) — 가이드 참고 |
| GET | /projects/{id}/analytics/{overview,iteration,releases,activity,cycle-time,projections} | 분석 (viewer). 이터레이션 드릴다운은 ?iteration_id=를 받음 |
| GET | /projects/{id}/metrics/{velocity,burndown,story-types} | 지표 (viewer) |
| GET / PUT | /projects/{id}/preferences | 이 프로젝트에 대한 여러분의 보드 환경 설정 (member) |
이벤트
섹션 제목: “이벤트”| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/events | 커서 페이지네이션 이벤트 스트림 (viewer) |
쿼리 파라미터: since=<event_id>, types=story.created,story.transitioned,comment.created,…, limit=, cursor=. 응답은 next_cursor를 포함합니다. 본 마지막 event_id를 since로 전달해 재개하세요.
임포트 (owner)
섹션 제목: “임포트 (owner)”| Method | Path | Description |
|---|---|---|
| POST | /projects/{id}/import (+ /json) | Multipart 업로드. source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json. |
WebSocket
섹션 제목: “WebSocket”wss://eastagiletracker.com/ws/control?token=<key>상호작용 UI 원격 제어용({ "action": "get_state", "id": "req-1" }). 데이터 채널이 아닙니다 — 모든 읽기/쓰기는 REST를 통합니다. 단일 인스턴스 전용. 복제본 간에 팬아웃되지 않습니다.
멱등성
섹션 제목: “멱등성”쓰기 엔드포인트(POST, PUT, DELETE)는 Idempotency-Key 헤더를 받습니다. 같은 키 + 같은 본문은 캐시된 응답을 재생합니다(24시간 창). 같은 키 + 다른 본문은 409 idempotency_conflict를 반환합니다. GET/HEAD/OPTIONS, /auth/*, /attachments 경로에는 적용되지 않습니다. 5xx 응답은 결코 캐시되지 않습니다 — 재시도는 핸들러에 도달합니다.
페이지네이션
섹션 제목: “페이지네이션”목록 엔드포인트는 cursor=<opaque>와 limit=<n≤200>을 받습니다. 설정되면 응답은 { "items": [...], "next_cursor": "<str|null>" }입니다. 페이징하려면 next_cursor를 다시 전달하세요. 일부 목록은 X-Tracker-Pagination-Total 헤더도 반환합니다.
필드 프로젝션
섹션 제목: “필드 프로젝션”목록 엔드포인트는 특정 필드만 반환하도록 fields=(쉼표로 구분)를 받습니다. story_id는 항상 포함됩니다. 알려지지 않은 필드 이름은 details.fields에 위반한 이름과 함께 400 validation_failed를 반환합니다.
GET /projects/123/stories?fields=story_id,name,current_state,owners오류 형식
섹션 제목: “오류 형식”모든 JSON 오류는 code와 error를 가집니다. 일부는 details를 더합니다:
{ "code": "invalid_transition", "error": "Cannot move story from `unstarted` to `accepted`", "details": { "from": "unstarted", "to": "accepted", "allowed": ["started"] } }| Status | code | When |
|---|---|---|
| 400 | invalid_parameter | 잘못된 입력; error에 메시지, details 없음(대부분의 검증: 공백/길이/널 바이트/이메일) |
| 400 | validation_failed | 구조화된 입력 오류; details.fields는 위반한 필드 이름의 배열 |
| 401 | unauthenticated | 토큰 누락/유효하지 않음 |
| 403 | unauthorized_operation | 인증되었으나 역할 부족 |
| 404 | unfound_resource | 찾을 수 없음 — 비멤버에게도 반환됨 |
| 409 | conflict | 리소스 충돌(예: 중복) |
| 409 | idempotency_conflict | Idempotency-Key가 다른 본문으로 재사용됨 |
| 422 | invalid_transition | 불법 상태 이동; details가 { from, to, allowed }를 담음 |
| 500 | internal_error | 서버 결함 — 일반 메시지; 재시도 안전 |
details.fields는 필드 이름의 JSON 배열(예: ["to"])이며, 때로 max 같은 추가 키를 포함합니다. 필드→메시지 맵은 없습니다.
{ "code": "validation_failed", "error": "unknown field(s): foo", "details": { "fields": ["foo"] } }속도 제한
섹션 제목: “속도 제한”키당(인증되지 않은 엔드포인트는 IP당), GCRA 토큰 버킷:
- Auth —
/auth/*: 0.5 req/s, burst 20. - Public —
/contact,/feedback: 0.2 req/s, burst 10. - Sensitive — 비밀번호 재설정: ~0.002 req/s, burst 5.
초과된 제한은 Retry-After 헤더와 평문 본문(JSON 오류 봉투가 아님)과 함께 429 Too Many Requests를 반환합니다.