Tuhmo API

อ่านและเขียนงาน โน้ต ลูกค้า และโปรเจกต์ใน Tuhmo จากระบบของคุณเอง และรับ webhook เมื่อมีอะไรเปลี่ยน

เริ่มต้น

สร้างคีย์ที่ ตั้งค่า แล้วเลือก นักพัฒนา หัวข้อคีย์ API คีย์แสดงครั้งเดียว เก็บไว้ในที่ปลอดภัย

ส่งคีย์ในหัว Authorization ของทุกคำขอ แล้วลองเรียก /me เพื่อดูว่าคีย์ใช้ได้

curl https://app.tuhmo.com/api/v1/me \
  -H "Authorization: Bearer tmk_..."

สิทธิ์ของคีย์

คีย์ทำงานในนามคนที่สร้าง ในเวิร์กสเปซที่สร้างเท่านั้น เห็นและแก้ได้เท่าที่คนนั้นทำได้ หน้าส่วนตัวของคนอื่นเข้าไม่ได้ ถ้าคนนั้นออกจากเวิร์กสเปซ คีย์ใช้ไม่ได้ทันที

คีย์มีสองแบบ อ่านอย่างเดียว กับ อ่านและเขียน แพ็กฟรีสร้างได้แบบอ่านอย่างเดียว 2 คีย์ต่อคน แพ็ก Plus ขึ้นไปสร้างได้ 10 คีย์ต่อคนและเขียนได้ เอกสารเงินอ่านได้อย่างเดียวทุกแพ็ก และ API ไม่มีคำสั่งส่งเอกสารถึงลูกค้า

เส้นทาง

ทุกเส้นขึ้นต้นด้วย https://app.tuhmo.com/api/v1 · {id} คือรหัสของสิ่งนั้น 24 ตัวอักษร · ส่งและรับเป็น JSON

วิธีเส้นทางใช้ทำอะไร
GET/meคีย์นี้เป็นของใคร เวิร์กสเปซไหน เขียนได้ไหม
GET/tasksรายการงาน
GET/tasks/{id}งานหนึ่งงาน
POST/tasksสร้างงาน (ต้องมี title และ status)
PATCH/tasks/{id}แก้บางช่องของงาน
DELETE/tasks/{id}ย้ายงานไปถังขยะ
PATCH/tasks/{id}/propsแก้คุณสมบัติที่เพิ่มเอง
GET/tasks/{id}/commentsคอมเมนต์ของงาน
POST/tasks/{id}/commentsเขียนคอมเมนต์ในงาน
GET/tasks/{id}/githubPR issue และ commit ของ GitHub ที่ผูกกับงาน
GET/tasksetsชุดงาน
GET/notes/treeโครงหน้าโน้ตทั้งหมดที่คุณเห็น
GET/notes/search?q=ค้นโน้ต
GET/notes/{id}โน้ตหนึ่งหน้า รวมเนื้อหา
POST/notesสร้างโน้ต
PATCH/notes/{id}แก้ชื่อหรือเนื้อหาโน้ต
DELETE/notes/{id}ย้ายโน้ตไปถังขยะ
GET/notes/{id}/commentsคอมเมนต์ในโน้ต
POST/notes/{id}/commentsเขียนคอมเมนต์ในโน้ต
GET/clientsรายการลูกค้า
GET/clients/{id}ลูกค้าหนึ่งราย
POST/clientsเพิ่มลูกค้า
PUT/clients/{id}แก้ข้อมูลลูกค้า
GET/clients/{id}/jobsโปรเจกต์ของลูกค้า
GET/projectsรายการโปรเจกต์
GET/projects/job/{id}โปรเจกต์หนึ่งโปรเจกต์
POST/jobsสร้างโปรเจกต์
PATCH/jobs/{id}แก้โปรเจกต์
GET/invoices · /invoices/{id}ใบแจ้งหนี้ (อ่านอย่างเดียว)
GET/proposals · /proposals/{id}ข้อเสนอ (อ่านอย่างเดียว)
GET/contracts · /contracts/{id}สัญญา (อ่านอย่างเดียว)

ตัวอย่าง: สร้างงาน

curl -X POST https://app.tuhmo.com/api/v1/tasks \
  -H "Authorization: Bearer tmk_..." \
  -H "Content-Type: application/json" \
  -d '{"title": "ส่งไฟล์ให้ลูกค้า", "status": "todo", "dueDate": "2026-10-20"}'

status เป็นได้ todo doing review หรือ done · dueDate เป็นรูปแบบ YYYY-MM-DD

งานทุกชิ้นมี number คือเลขงานสั้นในเวิร์กสเปซ (42 ใน TUH-42) ใส่เลขนี้ใน commit หรือ PR แล้วงานผูกกับ GitHub เอง ดู PR ที่ผูกได้ที่ /tasks/{id}/github

Webhook

ตั้งปลายทางที่ ตั้งค่า แล้วเลือก นักพัฒนา (เจ้าของและแอดมิน) แล้วเลือกเหตุการณ์ที่ต้องการ ทุกเหตุการณ์ส่งเป็น POST แบบ JSON ไปยัง URL ของปลายทาง

เนื้อโน้ตไม่ถูกส่ง ถ้าต้องการเนื้อให้เรียก /notes/{id} ด้วยคีย์ API · หน้าส่วนตัวและของที่อยู่ใต้หน้าส่วนตัวไม่ถูกส่งออก

eventส่งเมื่อdata มีอะไร
task.createdสร้างงานข้อมูลงานทั้งชิ้น
task.updatedแก้งาน เช่นชื่อ สถานะ วัน คนรับผิดชอบข้อมูลงานทั้งชิ้น
task.status_changedสถานะงานเปลี่ยน (ส่งคู่กับ task.updated)ข้อมูลงาน และ previousStatus
task.deletedย้ายงานไปถังขยะid title number url
note.createdสร้างหน้าโน้ตid title icon parentId projectId clientId เวลา url (ไม่มีเนื้อโน้ต)
note.updatedแก้โน้ต รวมเป็นครั้งเดียวเมื่อหยุดแก้ 30 วินาทีเหมือน note.created
note.deletedย้ายโน้ตไปถังขยะid title url
comment.createdมีคอมเมนต์ใหม่ในงาน โน้ต หรือแถวตารางข้อมูลคอมเมนต์ และ url ของที่คอมเมนต์อยู่
pingกดปุ่มทดสอบในหน้าตั้งค่าไม่มี data
{
  "id": "6720c1f2a9e4b3d1c0a1b2c3",
  "event": "task.status_changed",
  "at": "2026-10-20T09:30:00Z",
  "workspaceId": "66f0a8e2c4b1d2e3f4a5b6c7",
  "data": {
    "id": "6714e0b2a9e4b3d1c0a19f00",
    "previousStatus": "doing",
    "status": "review",
    "number": 42,
    "title": "...",
    "dueDate": "2026-10-20T00:00:00Z",
    "url": "https://app.tuhmo.com/tasks?task=6714e0b2a9e4b3d1c0a19f00"
  }
}

id บนสุดคือรหัสของการส่งครั้งนั้น ส่งซ้ำ (ลองใหม่) ได้ id เดิม ใช้กันรับซ้ำได้ · at คือเวลาที่เกิดเหตุการณ์ · data.id คือรหัสของงาน โน้ต หรือคอมเมนต์

ตรวจลายเซ็นและการลองใหม่

ทุกคำขอมีหัว X-Event (ชื่อเหตุการณ์) X-Delivery-Id (เท่ากับ id ในเนื้อ) และ X-Signature-256 เป็น HMAC SHA256 ของเนื้อคำขอดิบ เซ็นด้วยค่าลับ whsec_ ของปลายทาง ตรวจให้ตรงก่อนเชื่อข้อมูล

import crypto from "node:crypto";

// body = เนื้อคำขอดิบ (ก่อน JSON.parse) · secret = ค่าลับ whsec_ ของปลายทาง
function verify(body, header, secret) {
  const sig = "sha256=" + crypto.createHmac("sha256", secret).update(body).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(header ?? ""));
}

ปลายทางต้องตอบ 2xx ภายใน 15 วินาที ไม่อย่างนั้นระบบลองใหม่อีก 5 ครั้งในราว 10 ชั่วโมง ส่งไม่สำเร็จติดกัน 20 ครั้งระบบปิดปลายทางเองและแจ้งในกล่องเข้า

แพ็กฟรีมีได้ 1 ปลายทาง ส่งได้ 100 ครั้งต่อชั่วโมง แพ็ก Plus ขึ้นไปมีได้ 10 ปลายทาง ส่งได้ 1,000 ครั้งต่อชั่วโมงต่อปลายทาง

Webhook ขาเข้า

ให้ระบบอื่นส่งข้อมูลเข้า Tuhmo ด้วย URL เดียว ไม่ต้องใช้คีย์ เหมาะกับ GitHub Actions Zapier หรือฟอร์ม สร้าง URL ที่ ตั้งค่า แล้วเลือก นักพัฒนา หัวข้อ Webhook ขาเข้า (เจ้าของและแอดมิน แพ็ก Plus ขึ้นไป)

URL ทำงานในนามคนสร้าง เห็นและแก้ได้เท่าที่คนนั้นทำได้ URL แสดงครั้งเดียว ใครได้ URL ไปก็ส่งข้อมูลเข้าได้ ถ้าหลุดให้สร้าง URL ใหม่ URL เดิมใช้ไม่ได้ทันที

ส่ง POST เป็น JSON ระบุ action ได้สามแบบ ไม่แตะเอกสารเงินและส่งอะไรถึงลูกค้าไม่ได้

actionช่องที่ใช้ทำอะไร
create_tasktitle note status dueDate projectId clientIdสร้างงาน status ไม่ใส่จะเป็น todo
append_to_notenoteId textต่อข้อความท้ายโน้ต
add_commenttaskId หรือ noteId และ textเขียนคอมเมนต์ในงานหรือโน้ต
curl -X POST https://app.tuhmo.com/api/hooks/in/tih_... \
  -H "Content-Type: application/json" \
  -d '{"action": "create_task", "title": "Build ล้มบน main", "dueDate": "2026-10-20"}'

สำเร็จตอบ 201 หรือ 200 พร้อม id ของสิ่งที่สร้าง · URL ที่ปิดไว้ตอบ 403 code disabled · ไม่เกิน 60 ครั้งต่อนาทีต่อ URL เนื้อคำขอไม่เกิน 256 KB

ทุกคำขอบันทึกไว้ 14 วัน ดูได้ที่เมนูของ URL นั้น บอกว่าทำอะไร สำเร็จไหม และมาจาก IP ไหน

เพดาน

เฉลี่ย 3 คำขอต่อวินาทีต่อคีย์ ยิงรวดเดียวได้ถึง 10 และไม่เกิน 10 คำขอต่อวินาทีต่อเวิร์กสเปซ เกินแล้วได้ 429 พร้อมหัว Retry-After บอกว่าต้องรอกี่วินาที

เนื้อคำขอไม่เกิน 1 MB

รหัสข้อผิดพลาด

ข้อผิดพลาดตอบเป็น JSON มี error เป็นข้อความ และ code ให้โปรแกรมใช้ตัดสิน ส่งหัว Accept-Language: th เพื่อรับข้อความภาษาไทย

สถานะcodeความหมาย
401unauthorizedไม่มีคีย์ คีย์ผิด หมดอายุ หรือถูกเพิกถอน
403read_onlyคีย์อ่านอย่างเดียวพยายามแก้ข้อมูล
403planแพ็กของเวิร์กสเปซไม่รองรับ (เช่นแก้ข้อมูลในแพ็กฟรี)
403เจ้าของคีย์ไม่มีสิทธิ์ทำสิ่งนั้นในเวิร์กสเปซ
403disabledURL ของ webhook ขาเข้าถูกปิดไว้
404not_foundเส้นทางนี้ไม่ได้เปิดใน API หรือไม่พบสิ่งที่ขอ
413too_largeเนื้อคำขอเกิน 1 MB (webhook ขาเข้า 256 KB)
429rate_limitedเรียกถี่เกินเพดาน รอตาม Retry-After