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}/github | PR 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_task | title note status dueDate projectId clientId | สร้างงาน status ไม่ใส่จะเป็น todo |
| append_to_note | noteId text | ต่อข้อความท้ายโน้ต |
| add_comment | taskId หรือ 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 | ความหมาย |
|---|---|---|
| 401 | unauthorized | ไม่มีคีย์ คีย์ผิด หมดอายุ หรือถูกเพิกถอน |
| 403 | read_only | คีย์อ่านอย่างเดียวพยายามแก้ข้อมูล |
| 403 | plan | แพ็กของเวิร์กสเปซไม่รองรับ (เช่นแก้ข้อมูลในแพ็กฟรี) |
| 403 | เจ้าของคีย์ไม่มีสิทธิ์ทำสิ่งนั้นในเวิร์กสเปซ | |
| 403 | disabled | URL ของ webhook ขาเข้าถูกปิดไว้ |
| 404 | not_found | เส้นทางนี้ไม่ได้เปิดใน API หรือไม่พบสิ่งที่ขอ |
| 413 | too_large | เนื้อคำขอเกิน 1 MB (webhook ขาเข้า 256 KB) |
| 429 | rate_limited | เรียกถี่เกินเพดาน รอตาม Retry-After |

