เอกสารอ้างอิง endpoint REST ฉบับสมบูรณ์ สำหรับบทเรียนและตัวอย่าง ดู คู่มือ API
ทุกอย่างที่ สมาชิก (member) ของโปรเจกต์ทำได้ใน UI เว็บ มีให้ใช้ที่นี่ — SPA ใช้ API เดียวกันนี้ การดำเนินการที่ต้องการบทบาท ผู้จัดการ (manager) ถูกทำเครื่องหมาย (manager) ทุกอย่างที่เหลือต้องการเพียงสมาชิกภาพโปรเจกต์ (หรือสำหรับการอ่านที่ทำเครื่องหมาย (viewer) ต้องการระดับการเข้าถึงใดก็ได้) ตารางด้านล่างระบุกลุ่มเส้นทางทุกกลุ่มที่เซิร์ฟเวอร์เมานต์ไว้ กลุ่มที่สรุปไว้ในบรรทัดเดียวมีคำอธิบายครบถ้วนใน openapi.json แบบสด
ฐาน (Base)
หัวข้อที่มีชื่อว่า “ฐาน (Base)”https://eastagiletracker.com/api/v1https://api.eastagiletracker.com/api/v1 ให้บริการ API ที่เหมือนกัน คำขอและการตอบกลับทั้งหมดเป็น JSON ยกเว้น endpoint อัปโหลดไฟล์ไม่กี่ตัวที่รับ multipart
สองกลุ่มอยู่สูงขึ้นไปหนึ่งระดับ ใต้ /api แทนที่จะเป็น /api/v1: ส่วนการยืนยันตัวตน (/api/auth/*) และแบบฟอร์มสาธารณะ (/api/contact, /api/feedback) หากสะกดเป็น /api/v1/… จะได้ 404
การยืนยันตัวตน (Authentication)
หัวข้อที่มีชื่อว่า “การยืนยันตัวตน (Authentication)”ทุกคำขอที่ยืนยันตัวตนส่งข้อมูลรับรองผ่านหนึ่งใน:
X-TrackerToken: <key>Authorization: Bearer <key>
คีย์ผู้ใช้ขึ้นต้นด้วย ea_user_ คีย์เอเจนต์ขึ้นต้นด้วย ea_agent_ และโทเคนการเข้าถึง MCP ขึ้นต้นด้วย ea_mcp_ ดู คู่มือ API → ข้อมูลรับรองสามชนิด
endpoint ที่ไม่ต้องยืนยันตัวตน: /openapi.json, /docs, endpoint /api/auth/* และการค้นหาข้อมูลอ้างอิง (/story_types, /story_states, /effort_scales, /priority_scales) /meta ต้องยืนยันตัวตน — คีย์ที่ถูกต้องใด ๆ ใช้ได้ แต่มันไม่ได้กำหนดขอบเขตรายโปรเจกต์ (คีย์เอเจนต์ที่ผูกกับโปรเจกต์ก็เข้าถึงมันได้)
บทบาท (Roles)
หัวข้อที่มีชื่อว่า “บทบาท (Roles)”สี่ระดับเป็นด่านสำหรับ endpoint ที่กำหนดขอบเขตรายโปรเจกต์:
| ระดับ | ใครผ่าน | การดำเนินการทั่วไป |
|---|---|---|
| public viewer | ทุกคน บนโปรเจกต์ที่ตั้งการมองเห็นเป็นสาธารณะ | การอ่านบอร์ด: story, รอบงาน, การค้นหา, กิจกรรมของ story และ epic (โดยปกปิดรายละเอียดของผู้กระทำ) |
| viewer | viewer, member, manager | การอ่าน (list/get story, ค้นหา, เมตริก, รายการรูปแบบการส่งออก) |
| member | member, manager | การเขียน work-item ทั้งหมด (story, task, comment, …) และสตรีมเหตุการณ์ |
| manager | manager เท่านั้น | การตั้งค่าโปรเจกต์ การจัดการสมาชิกภาพ คีย์เอเจนต์ การลบ การนำเข้า การดาวน์โหลดไฟล์ส่งออก การสำรองข้อมูล บันทึกการตรวจสอบ |
เอเจนต์มีบทบาทชุดเดียวกับสมาชิก — viewer, member หรือ manager — โดยมีเพดานอยู่ที่บทบาทของสมาชิกผู้สร้างคีย์ ผู้ที่ไม่ใช่สมาชิกจะได้รับ 404 unfound_resource (ไม่ใช่ 403) บน path ของโปรเจกต์ส่วนตัว ดังนั้น ID ของโปรเจกต์จึงนับไล่ไม่ได้
endpoint ที่อธิบายตัวเอง
หัวข้อที่มีชื่อว่า “endpoint ที่อธิบายตัวเอง”| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /openapi.json | ข้อกำหนด OpenAPI 3 แบบสด รวมถึง request body ไม่ต้องยืนยันตัวตน |
| GET | /docs | Swagger UI ไม่ต้องยืนยันตัวตน |
| GET | /meta | ตัวตนของผู้เรียก (auth.kind/key_id/agent_id/project_id) + กราฟการเปลี่ยนสถานะรายประเภท story ต้องยืนยันตัวตน (คีย์ที่ถูกต้องใด ๆ ไม่กำหนดขอบเขตรายโปรเจกต์) เรียกสิ่งนี้ก่อน |
| GET | /api/health · /api/config | สถานะการทำงาน (liveness) และการกำหนดค่าสาธารณะของดีพลอยเมนต์ (โหมดองค์กรเดียว ฟีเจอร์เสริมที่เปิดใช้ ชื่ออินสแตนซ์) ไม่ต้องยืนยันตัวตน อยู่นอก /v1 |
Auth (/api/auth/* อยู่นอก /v1)
หัวข้อที่มีชื่อว่า “Auth (/api/auth/* อยู่นอก /v1)”endpoint ของเซสชัน ไม่ต้องยืนยันตัวตนเว้นแต่จะระบุไว้ SPA เป็นผู้ใช้ endpoint เหล่านี้ ส่วนสคริปต์โดยปกติใช้คีย์ API แทน
| Method | Path | คำอธิบาย |
|---|---|---|
| POST | /auth/register | ลงทะเบียนบัญชีใหม่ — มี reCAPTCHA ป้องกัน จากนั้นบัญชีต้องผ่านการยืนยันทาง SMS |
| POST | /auth/sms/challenge · /auth/sms/status · /auth/sms/bypass | ส่ง / ตรวจสอบรหัส SMS สำหรับการสมัคร (bypass ถูกควบคุมโดยผู้ดูแลระบบ) |
| GET | /auth/config | ดีพลอยเมนต์เปิดให้ลงชื่อเข้าใช้ด้วยวิธีใดบ้าง |
| POST | /auth/login | ลงชื่อเข้าใช้ด้วยอีเมล + รหัสผ่าน คืน JWT ของเซสชัน หรือคำท้า TOTP |
| POST | /auth/login/totp | ลงชื่อเข้าใช้ให้เสร็จด้วยรหัสจากแอปยืนยันตัวตนหรือรหัสกู้คืน |
| POST | /auth/passkey/login/start · /auth/passkey/login/finish | ลงชื่อเข้าใช้แบบไม่ใช้รหัสผ่านด้วย WebAuthn |
| GET | /auth/oauth/github/start · /auth/oauth/github/callback · /auth/oauth/google/start · /auth/oauth/google/callback · POST /auth/oauth/exchange | ลงชื่อเข้าใช้ด้วย OAuth ผ่าน GitHub หรือ Google |
| POST | /auth/refresh · /auth/refresh/revoke | หมุน refresh token / เพิกถอนมัน |
| POST | /auth/logout | ลงชื่อออก (เพิกถอน refresh token) |
| POST | /auth/forgot-password · /auth/reset-password | ขออีเมลรีเซ็ต / ใช้โทเคนรีเซ็ต |
| POST | /auth/accept-invite/lookup · /auth/accept-invite | แปลงโทเคนคำเชิญ → อีเมล / ยอมรับคำเชิญโปรเจกต์ (หลังยืนยันตัวตน) |
บัญชี / ตัวตน
หัวข้อที่มีชื่อว่า “บัญชี / ตัวตน”สิ่งเหล่านี้ทำหน้าที่กับผู้เรียกและต้องการเพียงคีย์ที่ถูกต้อง (ไม่ต้องมีบทบาทโปรเจกต์)
| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /me | โปรไฟล์ผู้ใช้ปัจจุบัน |
| PUT | /me | อัปเดตโปรไฟล์ |
| DELETE | /me | ลบบัญชี — ถูกปฏิเสธขณะที่คุณเป็นเจ้าของคนเดียวขององค์กร หรือของโปรเจกต์ที่มีสมาชิกคนอื่น |
| GET | /me/deletion-impact | การลบบัญชีจะนำอะไรออกไปบ้าง และอะไรขวางมันอยู่ |
| 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/totp · POST /me/totp/setup · /me/totp/verify · /me/totp/disable | การลงทะเบียนการยืนยันตัวตนสองชั้น (TOTP) โดย verify คืนรหัสกู้คืนเพียงครั้งเดียว |
| GET | /me/passkeys · POST /me/passkeys/register/start · /me/passkeys/register/finish · DELETE /me/passkeys/{credential_id} | การลงทะเบียนและการลบ passkey |
| GET | /me/oauth_grants · DELETE /me/oauth_grants/{grant_id} | แอปที่เชื่อมต่อ — ไคลเอนต์ MCP และแอป OAuth ที่คุณให้สิทธิ์ไว้ |
| GET | /me/activity | กิจกรรมของคุณในทุกโปรเจกต์ |
| GET | /me/stories | story ที่คุณเป็นเจ้าของ เป็นผู้ขอ หรือติดตาม ในทุกโปรเจกต์ที่โทเคนเข้าถึงได้ — role=owned|requested|following, state=, cursor= / limit= (สูงสุด 200) |
| GET | /me/mentions · POST /me/mentions/{mention_id}/ack | กล่อง @-กล่าวถึง (unacked=true เพื่อกรอง) และการรับทราบ — รวมอยู่ในฟีดการแจ้งเตือนด้านล่างด้วย |
| GET | /me/data-export | การส่งออกข้อมูลของคุณเองตาม GDPR |
| GET | /me/consent · POST /me/consent | อ่าน / บันทึกความยินยอม ({ consent_type, granted }) |
| GET | /legal/pending · POST /legal/accept | เอกสาร clickwrap ที่รอดำเนินการ / บันทึกการยอมรับ |
| GET / PUT | /agent/me | ตัวตนและโปรไฟล์ของคีย์เอเจนต์เอง ซึ่งเอเจนต์อ่านและแก้ไขได้ (คู่ฝั่งเอเจนต์ของ /me) |
| POST | /api/contact · /api/feedback · /api/feedback/with-screenshot | ติดต่อ + ฟีดแบ็กในแอป อยู่นอก /v1 จำกัดอัตรารายIP |
ข้อมูลอ้างอิง (ไม่ต้องยืนยันตัวตน)
หัวข้อที่มีชื่อว่า “ข้อมูลอ้างอิง (ไม่ต้องยืนยันตัวตน)”การค้นหา 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 | ค่าแต้มในมาตรวัด |
| GET | /priority_scales · /priority_scales/{scale_id}/values | มาตรวัดลำดับความสำคัญและค่าของมัน (priority_id บน story อ้างอิงมาที่นี่) |
องค์กร (Organizations)
หัวข้อที่มีชื่อว่า “องค์กร (Organizations)”เฉพาะบริการแบบโฮสต์ — การติดตั้งแบบโฮสต์เองทำงานในโหมดองค์กรเดียวและไม่ได้เมานต์ endpoint เหล่านี้ (ยกเว้นรายการองค์กร) บทบาทในที่นี้เป็นบทบาทขององค์กร: owner, admin, member
| Method | Path | คำอธิบาย |
|---|---|---|
| GET / POST | /organizations | แสดงรายการองค์กรของคุณ / สร้างองค์กร |
| GET / PUT / DELETE | /organizations/{oid} | อ่าน เปลี่ยนชื่อ (ชื่อ + slug; owner หรือ admin) ลบ |
| GET / POST | /organizations/{oid}/memberships · PUT / DELETE …/memberships/{member_id} | สมาชิกและคำเชิญ คำเชิญมีเพดานบทบาท (ไม่สูงกว่าบทบาทของผู้เรียก และไม่มีการเชิญเป็น owner) |
| POST | /organizations/{oid}/memberships/bulk-role · …/memberships/bulk-remove | เปลี่ยนบทบาทหรือนำสมาชิกออกได้สูงสุด 200 คนในครั้งเดียว ทั้งหมดหรือไม่มีเลย: ชุดคำขอที่จะนำ owner คนสุดท้ายออกหรือทำให้โปรเจกต์ไม่มีเจ้าของจะถูกปฏิเสธทั้งชุด เมื่อระบุ reassign_confirmed คุณจะกลายเป็นเจ้าของโปรเจกต์เหล่านั้นแทน |
| DELETE | /organizations/{oid}/invitations/{invitation_id} | เพิกถอนคำเชิญที่รอดำเนินการ |
| POST | /organizations/{oid}/transfer-ownership | ส่งต่อบทบาท owner ให้สมาชิกคนอื่น |
| PUT | /organizations/{oid}/memberships/{member_id}/anonymization | ปกปิดชื่อ / อีเมล / รูปแทนตัวของสมาชิกทั่วทั้งองค์กร |
| GET | /organization-invitations/{token} · POST …/{token}/accept | แปลง / ยอมรับคำเชิญเข้าองค์กรที่ส่งทางอีเมล |
| POST | /organizations/{oid}/export · GET / POST …/export/jobs · GET …/export/jobs/{job_id} · …/export/jobs/{job_id}/download | การส่งออกองค์กรเฉพาะ owner: ไฟล์ zip ที่มี SQL dump และไฟล์แนบทุกไฟล์ รันเป็นงาน (job) |
โปรเจกต์ (Projects)
หัวข้อที่มีชื่อว่า “โปรเจกต์ (Projects)”| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /projects | แสดงรายการโปรเจกต์ของคุณ (limit ≤ 200) |
| POST | /projects | สร้างโปรเจกต์ |
| GET | /projects/{id} | ดูรายละเอียดโปรเจกต์ (viewer) |
| PUT | /projects/{id} | อัปเดตการตั้งค่าโปรเจกต์ (manager) |
| DELETE | /projects/{id} | ลบโปรเจกต์ (manager) |
| POST | /projects/{id}/pin | ปักหมุด / เลิกปักหมุดโปรเจกต์บนรายการโปรเจกต์ของคุณ |
| POST | /projects/{id}/transfer-organization | ย้ายโปรเจกต์ไปยังองค์กรอื่น (manager) |
| POST | /projects/{id}/slack/test | ส่งข้อความทดสอบไปยังฟีด Slack ของโปรเจกต์ (manager) |
| GET / POST | /projects/{id}/showcase_claim_eligibility · /projects/{id}/showcase_claim · /projects/{id}/showcase_seed | โปรเจกต์ตัวอย่างสาธารณะ (showcase): ตรวจว่าคุณอ้างสิทธิ์ได้หรือไม่ อ้างสิทธิ์ และเติมข้อมูลตั้งต้น |
| GET | /projects/{id}/audit-log | การอ่าน audit log — ประวัติโปรเจกต์รวมถึงกิจกรรมราย story / ราย epic ผ่าน surface=; สิทธิ์การเข้าถึงต่างกันตาม surface ดูด้านล่าง |
| GET | /projects/{id}/events | สตรีมเหตุการณ์ที่แบ่งหน้าด้วย cursor (member) — ดู Events |
พารามิเตอร์ query ของ audit log: event_type= (ชนิดเดียวหรือรายการคั่นด้วยจุลภาค), limit= (≤ 1000), before= (keyset cursor, created_at แบบ ISO-8601), surface= (project_history, story_activities, epic_activities), target_id= (id ของ story/epic — จำเป็นเมื่อ surface=story_activities หรือ epic_activities) การเข้าถึง: log ที่ไม่กรองและ surface=project_history เป็น (manager); story_activities / epic_activities สมาชิกโปรเจกต์คนใดก็อ่านได้ และอ่านแบบไม่ระบุตัวตนได้ในโปรเจกต์สาธารณะ โดย PII ของผู้กระทำจะถูกปกปิด
สมาชิก เอเจนต์ และคีย์เอเจนต์
หัวข้อที่มีชื่อว่า “สมาชิก เอเจนต์ และคีย์เอเจนต์”| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /projects/{id}/memberships | แสดงรายการสมาชิก (viewer) |
| POST | /projects/{id}/memberships | เชิญสมาชิกทางอีเมล (manager) |
| PUT | /projects/{id}/memberships/{mid} | อัปเดตบทบาท (manager) |
| DELETE | /projects/{id}/memberships/{mid} | นำสมาชิกออก (manager) |
| GET | /projects/{id}/addable-members · POST /projects/{id}/members/add-existing | สมาชิกองค์กรที่ยังไม่อยู่ในโปรเจกต์ / เพิ่มหนึ่งคนโดยไม่ต้องส่งคำเชิญทางอีเมล (manager) |
| POST | /projects/{id}/members/join | owner หรือ admin ขององค์กรเข้าร่วมโปรเจกต์ในองค์กรของตนในฐานะ manager หรือเลื่อนตัวเองขึ้นเป็น manager (การดำเนินการ Make me owner บนรายการโปรเจกต์) |
| PUT | /projects/{id}/members/{mid}/anonymization | ปกปิดชื่อ / อีเมล / รูปแทนตัวของสมาชิกในโปรเจกต์นี้ (manager) |
| GET / POST | /projects/{id}/agent_keys | แสดงรายการ / สร้างคีย์เอเจนต์ — ผู้จัดการ หรือบทบาทที่นโยบาย creator-roles ของโปรเจกต์อนุญาต |
| DELETE | /projects/{id}/agent_keys/{kid} | เพิกถอนคีย์เอเจนต์ |
| GET | /projects/{id}/agent_keys/onboarding | ชุดเริ่มต้นใช้งาน (onboarding bundle): prompt และไฟล์กำหนดค่าสำหรับไคลเอนต์เอเจนต์ที่ใช้กันทั่วไป |
| GET | /projects/{id}/agents · GET / PUT /projects/{id}/agents/{aid} | เอเจนต์ของโปรเจกต์และโปรไฟล์ของพวกมัน (ชื่อ อักษรย่อ คำอธิบาย สี) |
| POST | /projects/{id}/agents/{aid}/rotate-key · /projects/{id}/agents/{aid}/avatar | หมุนคีย์ของเอเจนต์ (คงตัวตนและประวัติไว้) / อัปโหลดรูปแทนตัวของมัน |
การเขียน 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/{sid}/reject · /projects/{id}/stories/{sid}/restart | ปฏิเสธ story ที่ delivered แล้ว / นำ story ที่ถูกปฏิเสธกลับไปที่ started (rejected เป็นสถานะปลายทางสำหรับ /transitions) |
| POST | /projects/{id}/stories/{sid}/archive · /projects/{id}/stories/{sid}/unarchive | เก็บถาวร / ยกเลิกการเก็บถาวร story หนึ่งอัน |
| POST | /projects/{id}/stories/bulk_transition | เปลี่ยนสถานะหลาย story (1–100) พร้อมกัน |
| POST | /projects/{id}/stories/bulk-archive · bulk-delete · bulk-duplicate · bulk-move | เก็บถาวร ลบ ทำซ้ำ หรือย้าย (ไปยังแผง / ตำแหน่ง) หลาย story |
| POST | /projects/{id}/stories/{sid}/duplicate | ทำซ้ำ story หนึ่งอัน |
| GET / POST / DELETE | /projects/{id}/stories/{sid}/epics · …/epics/{eid} | การเป็นสมาชิก epic ของ story |
| GET | /short-links/{code} · /story-references | แปลงลิงก์สั้น /s/<code> เป็น story ของมัน / แปลงการอ้างอิง story ได้สูงสุด 100 รายการ (#id, URL) เป็น story ที่ผู้เรียกอ่านได้ |
พารามิเตอร์คิวรีของรายการ story: archived= (exclude เป็นค่าเริ่มต้น / include / only — ตัวกรองเก็บถาวรแบบสามสถานะ; มาแทน include_archived=true ที่เลิกใช้แล้ว ซึ่งตอนนี้เป็นชื่อแทนของ archived=include), include_done=true (ยอมรับ story ในแผง Done ที่ถูกตรึงไว้กับรอบงานที่ผ่านมา ค่าเริ่มต้นคือไม่รวม) การแบ่งหน้า (cursor= / limit= / offset=) และชุดฟิลด์แบบเลือกบางส่วน (fields=) เป็นไปตาม การแบ่งหน้า และ การฉายฟิลด์
Create (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? } โดย estimate คือ ป้ายกำกับ ของค่าบนมาตรวัดในรูปสตริง ("3", "13") ตัวเลข JSON จะถูกปฏิเสธ labels รับ ["auth"] หรือ [{ "name": "auth" }] ป้ายกำกับที่ไม่รู้จักจะถูกสร้างขึ้น ค่าเริ่มต้น: story_type=feature, current_state=unstarted
Update (PUT …/stories/{sid}): ฟิลด์เดียวกัน ทั้งหมดไม่บังคับ บวก "position" (float), "force_state_change" (bool) และ "expected_updated_at" (RFC 3339 — การบันทึกคำอธิบายจะถูกปฏิเสธด้วย 409 stale_write หาก story เปลี่ยนไปตั้งแต่คุณอ่านมัน) การเขียน story ยังรองรับ If-Match เทียบกับ ETag ของ story ด้วย หากไม่ตรงกันจะได้ 412 precondition_failed
Transition (POST …/transitions): { "to": "<state>" } ฟิลด์คือ to คืน { story_id, state } การย้ายที่ไม่ถูกต้อง → 422 invalid_transition พร้อม details: { from, to, allowed }
Bulk transition (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>" } แต่ละ 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 รับ fields= (รายการที่อนุญาต: comment_id, story_comment_id, story_id, comment_text, comment_emoji, member, created) พร้อมด้วย cursor= / limit= (≤ 200) / order=asc|desc |
| GET / POST | /projects/{id}/stories/{sid}/blockers · PUT/DELETE …/blockers/{bid} | { blocker_desc, resolved? } |
| GET / POST | /projects/{id}/stories/{sid}/links · PUT/DELETE …/links/{lid} | { url, link_type?, title? } — link_type ∈ relates_to, duplicates, blocks, is_blocked_by, pull_request, branch, other โดย URL /pull/ และ /tree/ ของ GitHub จะถูกกำหนดประเภทโดยอัตโนมัติ |
| GET / POST | /projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid} | สร้าง: { reviewer_id? / reviewer_agent_id?, comment? } — ละทั้งคู่เพื่อมอบหมายให้ตัวเอง อัปเดต: { 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 — วิดีโอ ≤ 200 MB, PDF / Word / Excel ≤ 25 MB, รูปภาพ / CSV / ข้อความ ≤ 10 MB; list เป็น (viewer) |
| GET / POST | /projects/{id}/stories/{sid}/link-attachments · DELETE …/link-attachments/{laid} | ไฟล์แนบแบบลิงก์ — URL ภายนอกที่เก็บไว้เคียงข้างไฟล์แนบ แทนที่จะเป็นลิงก์โค้ด |
| GET | /attachments/{token} · /api/avatars/{token} | การอ่านไฟล์แนบหรือรูปแทนตัวโดยอ้างด้วยโทเคน — URL ที่ API แจกให้ ไม่ต้องใช้ X-TrackerToken |
รูปแบบเดียวกับ story แต่ไม่มีเครื่องสถานะ member สำหรับการเขียน (viewer) สำหรับการอ่าน
| Method | Path | คำอธิบาย |
|---|---|---|
| GET / POST | /projects/{id}/epics · GET / PUT / DELETE …/epics/{eid} | epic มีชื่อ คำอธิบายแบบ Markdown และป้ายกำกับเบื้องหลังที่รวม story ของมันเข้าด้วยกัน |
| GET / POST / PUT / DELETE | …/epics/{eid}/comments · …/comments/{cid} | ความคิดเห็นของ epic |
| GET / POST / DELETE | …/epics/{eid}/owners · …/followers (+ รูปแบบ /agents/{aid}) | เจ้าของและผู้ติดตาม เป็นสมาชิกหรือเอเจนต์ก็ได้ — เจ้าของของ epic จะส่งต่อไปยัง story ของมัน |
| GET / POST / DELETE | …/epics/{eid}/attachments (+ /json) · …/link-attachments | ไฟล์แนบ เพดานเดียวกับ story |
| GET | /projects/{id}/analytics/epics · …/analytics/epics/{eid} | ความคืบหน้าราย epic: burnup, throughput, สุขภาพ, การพยากรณ์ (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 | แสดงรายการรอบงาน (≤ 500 ต่อหน้า มี ETag และ header ต่อหน้า X-Tracker-Pagination-* เมื่อถูกตัด) |
| GET | /projects/{id}/iterations/{itid} | รอบงานหนึ่งรอบ |
| GET | /projects/{id}/iterations/first-preview | วันที่ที่รอบงานแรกจะได้รับ ซึ่งแสดงในการยืนยันการตั้งต้นรอบงาน |
| POST | /projects/{id}/iterations | สร้างรอบงานด้วยตนเอง (member) |
| DELETE | /projects/{id}/iterations/{itid} | ลบรอบงาน (manager) |
| PUT | /projects/{id}/iterations/{itid}/velocity | แทนที่ความเร็วของรอบงานหนึ่งโดยไม่เปลี่ยนกลยุทธ์ของโปรเจกต์ (manager) |
| GET | /projects/{id}/iterations/{itid}/done-stories | story ที่ตรวจรับแล้วของรอบงานที่ปิดแล้ว แบบแบ่งหน้า |
การค้นหา เมตริก การตั้งค่า
หัวข้อที่มีชื่อว่า “การค้นหา เมตริก การตั้งค่า”| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /projects/{id}/search?q=… | การค้นหาอันทรงพลัง — เต็มข้อความ + qualifier ด้านแง่มุม / ช่วงวันที่ / บุคคล (DSL แบบ GitHub) คืน { results, total, limit, offset } โดย query เป็นชื่อพ้องของ q; limit= (ค่าเริ่มต้น 50 สูงสุด 1000) / offset= ใช้แบ่งหน้า; sort= เรียงตาม relevance (ค่าเริ่มต้น), created, created_asc, state หรือ updated (viewer) — ดู คู่มือ |
| GET | /projects/{id}/metrics/{velocity,burndown,story-types,contributors} | ชุดข้อมูลของหน้า Metrics (viewer) ส่วนเมตริกของ epic อยู่ใต้ /analytics/epics ด้านบน |
| GET | /projects/{id}/backlog/grouping | กลุ่มรอบงานที่ฉายภาพไว้ของ Backlog (viewer) |
| GET / PUT | /projects/{id}/preferences | การตั้งค่าบอร์ดของคุณสำหรับโปรเจกต์นี้ — บทบาทใดในโปรเจกต์ก็ได้ เฉพาะแถวของคุณเอง |
| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /projects/{id}/events | สตรีมเหตุการณ์ที่แบ่งหน้าด้วย cursor (member) — viewer จะได้ 403 |
พารามิเตอร์คิวรี: since=<event_id>, types=story.created,story.transitioned,comment.added,…, limit= (≤ 500), cursor= การตอบกลับรวม next_cursor ส่ง event_id สุดท้ายที่คุณเห็นเป็น since เพื่อกลับมาทำต่อ
การแจ้งเตือน
หัวข้อที่มีชื่อว่า “การแจ้งเตือน”ฟีดการแจ้งเตือนแบบรวมศูนย์ในแอป: แถวการแจ้งเตือนชั้นหนึ่ง (คำขอรีวิว กิจกรรมของ story คำเชิญ ฯลฯ) ผสานกับกล่อง @-กล่าวถึง เป็นสตรีมเดียวเรียงจากใหม่สุด id ของฟีดมีคำนำหน้าระบุแหล่งที่มา (nt-… / sc-… / ec-…) เซสชันสมาชิกและคีย์ ea_user_* อ่านแถวฝั่งสมาชิกของตน ส่วนคีย์ ea_agent_* อ่านแถวฝั่งเอเจนต์
| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /me/notifications | ฟีดการแจ้งเตือนของคุณ ตัวกรอง: unread=true, since_id=, kind= (mentions / reviews / stories / invitations); แบ่งหน้าโดย cursor= / limit= |
| GET | /me/notifications/unread-count | ยอดที่ยังไม่อ่าน — { unread_count, by_category: { mentions, reviews, stories, invitations } } |
| POST | /me/notifications/read-all | ทำเครื่องหมายอ่านแล้วทั้งหมด; คืนค่าตัวนับล่าสุด |
| POST | /me/notifications/{id}/ack | ทำเครื่องหมายอ่านแล้วหนึ่งรายการ (idempotent) |
| POST | /me/notifications/{id}/accept | ตอบรับคำเชิญเข้าโปรเจกต์ / องค์กรจากฟีด (เฉพาะโทเคนสมาชิก) |
| POST | /me/notifications/{id}/decline | ปฏิเสธคำเชิญเข้าโปรเจกต์ / องค์กร (เฉพาะโทเคนสมาชิก) |
| GET | /me/notifications/resolve-invite?token=… | จับคู่โทเคนคำเชิญที่ส่งทางอีเมลกับ id การแจ้งเตือนของคุณ — { "id": "nt-…" } หรือ { "id": null } |
| GET | /me/notifications/stream | พุชแบบเรียลไทม์ — Server-Sent Events (text/event-stream); ดูด้านล่าง |
endpoint แบบ stream ไม่ใช่ endpoint JSON จึงไม่อยู่ในสเปก OpenAPI: มันเปิดการเชื่อมต่อค้างไว้และส่งเฟรมที่ไม่มี payload ({"type":"notification","kind":…}) ทุกครั้งที่มีรายการใหม่ เพื่อบอกให้ไคลเอนต์ดึงฟีดใหม่ การเชื่อมต่อถูกจำกัดฝั่งเซิร์ฟเวอร์ไว้ที่ 45 นาที — ให้เชื่อมต่อและยืนยันตัวตนใหม่ ใช้ได้เฉพาะเซสชันสมาชิกและคีย์ ea_user_* ส่วนคีย์ ea_agent_* จะได้รับ 403
การนำเข้า (manager)
หัวข้อที่มีชื่อว่า “การนำเข้า (manager)”| Method | Path | คำอธิบาย |
|---|---|---|
| POST | /projects/{id}/import | แหล่งแบบไฟล์: source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json, eat multipart file= ทำงานแบบซิงโครนัส — ตอบกลับพร้อมจำนวนผลลัพธ์ |
| POST | /projects/{id}/import/json | body แบบ JSON; source=github ไม่ต้องใช้ไฟล์ — owner, repo, token (ไม่บังคับ) และแฟล็กแบบเลือกเข้าร่วม include_pull_requests / include_milestones / include_releases / include_dependencies ส่วนแหล่งแบบไฟล์ส่ง file_base64 อะซิงโครนัส: คืน 202 { import_id, status } เซิร์ฟเวอร์ดึงข้อมูลผ่าน GraphQL API ของ GitHub ซึ่งปฏิเสธผู้เรียกแบบไม่ระบุตัวตน ดังนั้นจึงมี token ไปถึง GitHub เสมอ — ของคุณเอง หรือ token ร่วมของดีพลอยเมนต์ ดู คู่มือ |
| GET | /projects/{id}/imports/{import_id} | poll งาน: status ดำเนินไปตาม pending → fetching → writing → done | failed พร้อม progress_current / progress_total ระหว่างการดึงข้อมูล และจำนวนผลลัพธ์เมื่อ done |
การนำเข้ารันได้ครั้งละหนึ่งงานต่อโปรเจกต์ POST ครั้งที่สองขณะที่มีงานหนึ่งกำลังรันอยู่จะได้ 409 import_already_running ส่วน dry_run: true (body JSON หรือ dry_run=true multipart) แสดงตัวอย่างแหล่งใดก็ได้: แยกวิเคราะห์ แก้ปัญหาการอ้างอิง ตัดข้อมูลซ้ำ คืนจำนวน { imported, skipped, errors, unmatched } เดียวกัน จากนั้นย้อนกลับ — ไม่มีอะไรถูกเขียน ข้อจำกัด: body 10 MiB และ 5,000 story ต่อการนำเข้าสำหรับแหล่งที่เป็นไฟล์ (เกินอย่างใดอย่างหนึ่ง → 400 ไม่เขียนอะไร) แหล่ง GitHub ไม่มีเพดาน — มันคอมมิตเป็นก้อน ๆ แทนที่จะเป็นทรานแซกชันเดียว การนำเข้าซ้ำเป็นแบบ idempotent ตาม source id — แถวที่ถูกนำเข้าไปแล้วจะถูกข้าม ไม่ถูกสร้างซ้ำ
การส่งออก
หัวข้อที่มีชื่อว่า “การส่งออก”| Method | Path | คำอธิบาย |
|---|---|---|
| GET | /projects/{id}/export/formats | รูปแบบที่ลงทะเบียนไว้: { id, name, content_type, drops, includes_archived } บทบาทใดในโปรเจกต์ก็ได้ |
| GET | /projects/{id}/export/{format} | ดาวน์โหลดหนึ่งรูปแบบ (manager) สำหรับแลกเปลี่ยน: eat (ความเที่ยงตรงเต็มรูปแบบ), jira, pivotal, shortcut, trello, asana, gitlab, linear, plane, plane_json; เอกสาร: pdf, docx |
| GET | /projects/{id}/export/attachments | ไฟล์แนบทุกอันเป็น zip เดียวที่เรียกดูได้ (ไฟล์คงชื่อเดิมไว้; ไฟล์รายการ JSON + CSV) (manager) |
การส่งออกเอกสาร (pdf, docx) รับพารามิเตอร์คิวรีเพิ่มเติม: page_size= (letter เป็นค่าเริ่มต้น / a4 / legal / folio), from= / to= (ขอบเขตช่วงของ story — RFC 3339 หรือ YYYY-MM-DD เปล่า ๆ; story อยู่ในช่วงเมื่อ created หรือ completed_at ของมันตกอยู่ในช่วงนั้น), include_icebox= / include_backlog= (ทั้งคู่ค่าเริ่มต้นเป็น false ดังนั้นการส่งออกเพื่อแชร์จะแสดงเฉพาะงานที่จัดตารางแล้ว / กำลังดำเนินอยู่) รูปแบบแลกเปลี่ยน CSV จะไม่สนใจพารามิเตอร์เหล่านี้
การสำรองและกู้คืนข้อมูล (manager)
หัวข้อที่มีชื่อว่า “การสำรองและกู้คืนข้อมูล (manager)”| Method | Path | คำอธิบาย |
|---|---|---|
| GET / POST | /projects/{id}/backups · GET …/backups/{snapshot_id} · …/backups/health | แสดงรายการสแนปช็อต สร้างหนึ่งอันทันที อ่านหนึ่งอัน และสรุปสุขภาพของการเก็บรักษา |
| GET / POST | /projects/{id}/restores · POST …/restores/partial · GET …/restores/{restore_id} | กู้คืนสแนปช็อตทั้งหมด หรือเฉพาะตารางที่เลือกจากสแนปช็อตหนึ่ง และ poll การกู้คืน |
POST เหล่านี้อยู่ในชั้นขีดจำกัดอัตรา sensitive (ด้านล่าง)
MCP และผู้ให้บริการ OAuth
หัวข้อที่มีชื่อว่า “MCP และผู้ให้บริการ OAuth”East Agile Tracker เป็นผู้ให้บริการ OAuth 2.1 สำหรับไคลเอนต์ MCP ไคลเอนต์ค้นพบมันที่ /.well-known/oauth-authorization-server และ /.well-known/oauth-protected-resource/mcp ส่งคุณไปที่ /oauth/authorize (หน้าให้ความยินยอม) แลกรหัสที่ /oauth/token จากนั้นสื่อสารด้วย MCP ที่ /mcp โดยใช้โทเคน ea_mcp_* ที่ได้มา การให้สิทธิ์ (grant) แสดงรายการและเพิกถอนได้ที่ /me/oauth_grants endpoint ของผู้ให้บริการมีชั้นขีดจำกัดอัตราของตัวเอง
WebSocket
หัวข้อที่มีชื่อว่า “WebSocket”wss://eastagiletracker.com/ws/control?token=<session JWT>สำหรับการควบคุม UI จากระยะไกลแบบโต้ตอบ ({ "action": "get_state", "id": "req-1" }) โทเคนคือ JWT ของเซสชันเบราว์เซอร์ — คีย์ API จะถูกปฏิเสธด้วย 401 ก่อนการอัปเกรดการเชื่อมต่อ ไม่ใช่ช่องข้อมูล — การอ่าน/เขียนทั้งหมดผ่าน REST ใช้ได้กับอินสแตนซ์เดียวเท่านั้น ไม่กระจายข้ามเรพลิกา
Idempotency
หัวข้อที่มีชื่อว่า “Idempotency”endpoint การเขียน (POST, PUT, DELETE) รับ header Idempotency-Key คีย์เดียวกัน + body เดียวกัน จะเล่นซ้ำการตอบกลับที่แคชไว้ (หน้าต่าง 24 ชั่วโมง) คีย์เดียวกัน + body ต่างกัน คืน 409 idempotency_conflict คีย์มีขอบเขตอยู่กับข้อมูลรับรองที่ส่งมันมา ไม่ใช้กับ GET/HEAD/OPTIONS, /openapi.json และ /docs, /api/auth/* หรือการอัปโหลดแบบ multipart บน path /attachments การตอบกลับที่หยุดก่อนจะได้คำตอบเชิงโดเมนจะไม่ถูกแคชเลย — 401, 403, 404, 429 และ 5xx ทุกตัว — ดังนั้นการลองใหม่หลังจากสิ่งเหล่านี้จะถึงตัวจัดการ (handler) ส่วน 400, 409, 412 และ 422 คือคำตอบของโดเมนและจะเล่นซ้ำเหมือนการตอบกลับที่สำเร็จ
การแบ่งหน้า (Pagination)
หัวข้อที่มีชื่อว่า “การแบ่งหน้า (Pagination)”endpoint แบบรายการรับ cursor=<opaque> และ limit=<n> เมื่อตั้งค่า การตอบกลับเป็น { "items": [...], "next_cursor": "<str|null>" } ส่ง next_cursor กลับเพื่อเลื่อนหน้า เพดานของ limit ต่างกันไปตาม endpoint: 200 สำหรับ story ความคิดเห็น และโปรเจกต์ 500 สำหรับ events และ 1000 สำหรับการค้นหาและบันทึกการตรวจสอบ
รายการแบบธรรมดา (ไม่มี cursor/limit) ที่ต้องตัดการตอบกลับจะแจ้งไว้ใน header — X-Tracker-Pagination-Truncated, X-Tracker-Pagination-Limit, X-Tracker-Pagination-Offset และ X-Tracker-Pagination-Next-Offset ส่งตัวสุดท้ายกลับเป็น offset= สำหรับหน้าถัดไป ไม่มี header จำนวนรวม
การฉายฟิลด์ (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 ต่างกัน |
| 409 | stale_write · import_already_running | story เปลี่ยนไปตั้งแต่ expected_updated_at ของคุณ · มีการนำเข้ากำลังรันอยู่แล้ว |
| 412 | precondition_failed | If-Match ไม่ตรงกับ ETag ปัจจุบันของทรัพยากร; details มี expected และ current |
| 413 | request_too_large | body เกินขีดจำกัดขนาดของเส้นทางนั้น |
| 422 | invalid_transition | การย้ายสถานะไม่ถูกต้อง details มี { from, to, allowed } |
| 429 | rate_limited | คำขอจาก IP นี้มากเกินไปบนเส้นทางที่จำกัดอัตรา; มี header Retry-After |
| 500 | internal_error | ความผิดพลาดของเซิร์ฟเวอร์ — ข้อความทั่วไป ลองใหม่ได้อย่างปลอดภัย |
| 503 | not_configured | ดีพลอยเมนต์ขาดการผสานรวมที่เส้นทางนี้ต้องใช้ (SMS, object storage, …) |
details.fields เป็น อาร์เรย์ JSON ของชื่อฟิลด์ (เช่น ["to"]) บางครั้งมีคีย์เพิ่มเติมอย่าง max ไม่มีแมประหว่างฟิลด์→ข้อความ
{ "code": "validation_failed", "error": "unknown field(s): foo", "details": { "fields": ["foo"] } }ขีดจำกัดอัตรา (Rate limits)
หัวข้อที่มีชื่อว่า “ขีดจำกัดอัตรา (Rate limits)”จำกัดรายIP ของไคลเอนต์ บนเส้นทางจำนวนหนึ่ง ทราฟฟิก API ที่ยืนยันตัวตนแล้วในที่อื่นไม่ถูกจำกัดอัตรา ค่าเริ่มต้น (แต่ละคู่คืออัตราต่อเนื่องและ burst ซึ่งผู้ดูแลระบบปรับได้):
- Auth —
/api/auth/*: 0.5 req/s burst 20 - OAuth provider —
/oauth/*: 1 req/s burst 60 - Public —
/api/contact: 0.2 req/s burst 10 - Feedback —
/api/feedback: สามชั้นซ้อนกัน — ส่งได้หนึ่งครั้งต่อ 15 วินาที 10 ครั้งต่อชั่วโมง 36 ครั้งต่อวัน - Avatars — การเปลี่ยนเส้นทางรูปแทนตัวที่ไม่ต้องยืนยันตัวตน: 20 req/s burst 200
- Sensitive —
POSTของการสำรองและกู้คืนข้อมูล: ~0.002 req/s burst 5
การเกินขีดจำกัดคืน 429 พร้อม header Retry-After และซองข้อผิดพลาด JSON มาตรฐาน code: "rate_limited"