เอกสารอ้างอิง endpoint REST ฉบับสมบูรณ์ สำหรับบทเรียนและตัวอย่าง ดู คู่มือ API
ทุกอย่างที่ สมาชิก (member) ของโปรเจกต์ทำได้ใน UI เว็บ มีให้ใช้ที่นี่ — SPA ใช้ API เดียวกันนี้ การดำเนินการที่ต้องการบทบาท เจ้าของ (owner) ถูกทำเครื่องหมาย (owner) ทุกอย่างที่เหลือต้องการเพียงสมาชิกภาพโปรเจกต์ (หรือสำหรับการอ่านที่ทำเครื่องหมาย (viewer) ต้องการระดับการเข้าถึงใดก็ได้)
ฐาน (Base)
หัวข้อที่มีชื่อว่า “ฐาน (Base)”https://eastagiletracker.com/api/v1https://api.eastagiletracker.com/api/v1 ให้บริการ API ที่เหมือนกัน คำขอและการตอบกลับทั้งหมดเป็น JSON ยกเว้น endpoint อัปโหลดไฟล์ไม่กี่ตัวที่รับ multipart
การยืนยันตัวตน (Authentication)
หัวข้อที่มีชื่อว่า “การยืนยันตัวตน (Authentication)”ทุกคำขอที่ยืนยันตัวตนส่งคีย์ API ผ่านหนึ่งใน:
X-TrackerToken: <key>Authorization: Bearer <key>
คีย์ผู้ใช้ขึ้นต้นด้วย ea_user_ คีย์เอเจนต์ขึ้นต้นด้วย ea_agent_ ดู คู่มือ API → คีย์สองชนิด
endpoint ที่ไม่ต้องยืนยันตัวตน: /openapi.json, /docs, endpoint /auth/* และการค้นหาข้อมูลอ้างอิง (/story_types, /story_states, /effort_scales, …) /meta ต้องยืนยันตัวตน — คีย์ที่ถูกต้องใด ๆ ใช้ได้ แต่มันไม่ได้กำหนดขอบเขตรายโปรเจกต์ (คีย์เอเจนต์ที่ผูกกับโปรเจกต์ก็เข้าถึงมันได้)
บทบาท (Roles)
หัวข้อที่มีชื่อว่า “บทบาท (Roles)”สามระดับเป็นด่านสำหรับ endpoint ที่กำหนดขอบเขตรายโปรเจกต์:
| ระดับ | ใครผ่าน | การดำเนินการทั่วไป |
|---|---|---|
| viewer | viewer, member, owner | การอ่าน (list/get story, ค้นหา, การวิเคราะห์) |
| member | member, owner | การเขียน work-item ทั้งหมด (story, task, comment, …) |
| owner | owner เท่านั้น | การตั้งค่าโปรเจกต์ การจัดการสมาชิกภาพ คีย์เอเจนต์ การลบ การนำเข้า บันทึกการตรวจสอบ |
ผู้ที่ไม่ใช่สมาชิกจะได้รับ 404 unfound_resource (ไม่ใช่ 403) บน path ของโปรเจกต์ ดังนั้น ID ของโปรเจกต์จึงนับลำดับไม่ได้
endpoint ที่อธิบายตัวเอง
หัวข้อที่มีชื่อว่า “endpoint ที่อธิบายตัวเอง”| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /openapi.json | ข้อกำหนด OpenAPI 3 แบบสด ไม่ต้องยืนยันตัวตน |
| GET | /docs | Swagger UI ไม่ต้องยืนยันตัวตน |
| GET | /meta | ตัวตนของผู้เรียก (auth.kind/key_id/agent_id/project_id) + กราฟการเปลี่ยนสถานะรายประเภท story ต้องยืนยันตัวตน (คีย์ที่ถูกต้องใด ๆ ไม่กำหนดขอบเขตรายโปรเจกต์) เรียกสิ่งนี้ก่อน |
บัญชี / ตัวตน
หัวข้อที่มีชื่อว่า “บัญชี / ตัวตน”สิ่งเหล่านี้ทำหน้าที่กับผู้เรียกและต้องการเพียงคีย์ที่ถูกต้อง (ไม่มีบทบาทโปรเจกต์)
| Method | Path | คำอธิบาย |
|---|---|---|
| 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} | จัดการคีย์ API ของผู้ใช้ (ea_user_) |
| GET | /me/activity | กิจกรรมของคุณในทุกโปรเจกต์ |
| GET | /me/data-export | การส่งออกข้อมูลของคุณเองตาม GDPR |
| GET | /me/consent · POST /me/consent | อ่าน / บันทึกความยินยอม ({ consent_type, granted }) |
| GET | /legal/pending · POST /legal/accept | เอกสาร clickwrap ที่รอดำเนินการ / บันทึกการยอมรับ |
| POST | /contact · POST /feedback · POST /feedback/with-screenshot | ติดต่อ + ฟีดแบ็กในแอป |
ข้อมูลอ้างอิง (ไม่ต้องยืนยันตัวตน)
หัวข้อที่มีชื่อว่า “ข้อมูลอ้างอิง (ไม่ต้องยืนยันตัวตน)”การค้นหา seed ที่ใช้เมื่อสร้าง/ประเมิน story ID เสถียร
| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /story_types | feature, bug, chore, release (+ allow_points) |
| GET | /story_states | unstarted … accepted, rejected |
| GET | /effort_scales | มาตรวัดการประเมินที่มีให้ |
| GET | /effort_scales/{scale_id}/values | ค่าแต้มในมาตรวัด |
โปรเจกต์ (Projects)
หัวข้อที่มีชื่อว่า “โปรเจกต์ (Projects)”| Method | Path | คำอธิบาย |
|---|---|---|
| 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 | สตรีมเหตุการณ์ที่แบ่งหน้าด้วย cursor (viewer) — ดู Events |
สมาชิกและคีย์เอเจนต์
หัวข้อที่มีชื่อว่า “สมาชิกและคีย์เอเจนต์”| Method | Path | คำอธิบาย |
|---|---|---|
| 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) |
การเขียน story ทั้งหมดต้องการบทบาท member
| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /projects/{id}/stories | แสดงรายการ story (แบ่งหน้า กรองได้) (viewer) |
| POST | /projects/{id}/stories | สร้าง story |
| GET | /projects/{id}/stories/{sid} | ดู story หนึ่งอัน (viewer) |
| PUT | /projects/{id}/stories/{sid} | อัปเดต story |
| DELETE | /projects/{id}/stories/{sid} | ลบ story |
| POST | /projects/{id}/stories/{sid}/transitions | เปลี่ยนสถานะพร้อมการตรวจสอบ |
| POST | /projects/{id}/stories/bulk_transition | เปลี่ยนสถานะหลาย story (1–100) พร้อมกัน |
| POST | /projects/{id}/stories/bulk-delete | ลบหลาย story |
| POST | /projects/{id}/stories/bulk-duplicate | ทำซ้ำหลาย story |
| POST | /projects/{id}/stories/{sid}/duplicate | ทำซ้ำ story หนึ่งอัน |
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 } การย้ายที่ไม่ถูกต้อง → 422 invalid_transition พร้อม details: { from, to, allowed }
Bulk transition (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>", "reason"? } แต่ละ story ถูกตัดสินอย่างอิสระ คืน { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }
ทรัพยากรย่อยของ story
หัวข้อที่มีชื่อว่า “ทรัพยากรย่อยของ story”ทั้งหมดเป็น member การ List/GET ส่วนใหญ่เป็น (viewer)
| Method | Path | Body / หมายเหตุ |
|---|---|---|
| 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) } หรือ { 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 ต่อไฟล์) list เป็น (viewer) |
ป้ายกำกับ (Labels)
หัวข้อที่มีชื่อว่า “ป้ายกำกับ (Labels)”member สำหรับการเขียน (viewer) สำหรับการอ่าน
| Method | Path | คำอธิบาย |
|---|---|---|
| GET / POST | /projects/{id}/labels | แสดงรายการ / สร้างป้ายกำกับ |
| PUT / DELETE | /projects/{id}/labels/{lid} | อัปเดต / ลบป้ายกำกับ |
| POST | /projects/{id}/labels/{lid}/archive | เก็บถาวร (ซ่อนแบบนุ่ม) ป้ายกำกับ |
รอบงาน (Iterations)
หัวข้อที่มีชื่อว่า “รอบงาน (Iterations)”| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /projects/{id}/iterations | แสดงรายการรอบงาน (member) |
| POST | /projects/{id}/iterations | สร้างรอบงานด้วยตนเอง (owner) |
| DELETE | /projects/{id}/iterations/{itid} | ลบรอบงาน (owner) |
การค้นหา การวิเคราะห์ เมตริก การตั้งค่า
หัวข้อที่มีชื่อว่า “การค้นหา การวิเคราะห์ เมตริก การตั้งค่า”| Method | Path | คำอธิบาย |
|---|---|---|
| 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 | คำอธิบาย |
|---|---|---|
| GET | /projects/{id}/events | สตรีมเหตุการณ์ที่แบ่งหน้าด้วย cursor (viewer) |
พารามิเตอร์คิวรี: since=<event_id>, types=story.created,story.transitioned,comment.created,…, limit=, cursor= การตอบกลับรวม next_cursor ส่ง event_id สุดท้ายที่คุณเห็นเป็น since เพื่อกลับมาทำต่อ
การนำเข้า (owner)
หัวข้อที่มีชื่อว่า “การนำเข้า (owner)”| Method | Path | คำอธิบาย |
|---|---|---|
| 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 ใช้ได้กับอินสแตนซ์เดียวเท่านั้น ไม่กระจายข้ามเรพลิกา
Idempotency
หัวข้อที่มีชื่อว่า “Idempotency”endpoint การเขียน (POST, PUT, DELETE) รับ header Idempotency-Key คีย์เดียวกัน + body เดียวกัน จะเล่นซ้ำการตอบกลับที่แคชไว้ (หน้าต่าง 24 ชั่วโมง) คีย์เดียวกัน + body ต่างกัน คืน 409 idempotency_conflict ไม่ใช้กับ GET/HEAD/OPTIONS, /auth/* หรือ path /attachments การตอบกลับ 5xx ไม่ถูกแคชเลย — การลองใหม่จะถึงตัวจัดการ (handler)
การแบ่งหน้า (Pagination)
หัวข้อที่มีชื่อว่า “การแบ่งหน้า (Pagination)”endpoint แบบรายการรับ cursor=<opaque> และ limit=<n≤200> เมื่อตั้งค่า การตอบกลับเป็น { "items": [...], "next_cursor": "<str|null>" } ส่ง next_cursor กลับเพื่อเลื่อนหน้า รายการบางอันยังคืน header X-Tracker-Pagination-Total ด้วย
การฉายฟิลด์ (Field projection)
หัวข้อที่มีชื่อว่า “การฉายฟิลด์ (Field projection)”endpoint แบบรายการรับ fields= (คั่นด้วยจุลภาค) เพื่อคืนเฉพาะฟิลด์ที่ระบุ story_id ถูกรวมเสมอ ชื่อฟิลด์ที่ไม่รู้จักจะคืน 400 validation_failed พร้อมชื่อที่ผิดใน details.fields
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"] } }| สถานะ | code | เมื่อใด |
|---|---|---|
| 400 | invalid_parameter | อินพุตไม่ถูกต้อง ข้อความใน error ไม่มี details (การตรวจสอบส่วนใหญ่: ว่าง/ความยาว/null-byte/email) |
| 400 | validation_failed | ข้อผิดพลาดอินพุตแบบมีโครงสร้าง details.fields เป็น อาร์เรย์ ของชื่อฟิลด์ที่ผิด |
| 401 | unauthenticated | โทเค็นขาดหาย/ไม่ถูกต้อง |
| 403 | unauthorized_operation | ยืนยันตัวตนแล้วแต่บทบาทไม่เพียงพอ |
| 404 | unfound_resource | ไม่พบ — คืนให้ผู้ที่ไม่ใช่สมาชิกด้วย |
| 409 | conflict | ทรัพยากรขัดแย้ง (เช่น ซ้ำกัน) |
| 409 | idempotency_conflict | Idempotency-Key ใช้ซ้ำกับ body ต่างกัน |
| 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"] } }ขีดจำกัดอัตรา (Rate limits)
หัวข้อที่มีชื่อว่า “ขีดจำกัดอัตรา (Rate limits)”รายคีย์ (รายIP สำหรับ endpoint ที่ไม่ต้องยืนยันตัวตน) ถังโทเค็นแบบ 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
การเกินขีดจำกัดคืน 429 Too Many Requests พร้อม header Retry-After และ body แบบ ข้อความธรรมดา (ไม่ใช่ซองข้อผิดพลาด JSON)