Tuhmo API

自社のシステムから Tuhmo のタスク、ノート、クライアント、プロジェクトを読み書きでき、変更があれば Webhook で通知を受け取れます。

はじめに

「設定」の「開発者」にある「API キー」でキーを作成します。キーは一度しか表示されないため、安全な場所に保管してください。

すべてのリクエストの Authorization ヘッダーにキーを付けて送信します。まず /me を呼び出して、キーが使えることを確認してください。

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

キーでできること

キーは作成した人として、作成したワークスペースの中でだけ動作します。閲覧や変更ができる範囲はその人と同じで、他の人のプライベートページにはアクセスできません。作成した人がワークスペースを離れると、キーはすぐに使えなくなります。

キーには「読み取り専用」と「読み取りと書き込み」の2種類があります。Free プランでは1人につき読み取り専用のキーを2つまで、Plus 以上では書き込みもできるキーを1人10個まで作成できます。お金に関する書類はどのプランでも読み取り専用で、API からクライアントに書類を送信する手段はありません。

エンドポイント

すべてのパスは https://app.tuhmo.com/api/v1 で始まります。{id} は対象の24文字の ID です。リクエストとレスポンスは JSON です。

メソッドパス内容
GET/meこのキーの所有者、ワークスペース、書き込み可否
GET/tasksタスク一覧
GET/tasks/{id}タスクを1件取得
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タスクに紐づく GitHub のプルリクエスト、Issue、コミット
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}クライアントを1件取得
POST/clientsクライアントを作成
PUT/clients/{id}クライアントを更新
GET/clients/{id}/jobsクライアントのプロジェクト
GET/projectsプロジェクト一覧
GET/projects/job/{id}プロジェクトを1件取得
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 があり、ワークスペース内の短い番号として使えます(TUH-42 の 42)。コミットやプルリクエストにこの番号を書くと、タスクが自動で GitHub と紐づきます。紐づいたプルリクエストは /tasks/{id}/github で確認できます。

Webhook

オーナーと管理者は「設定」の「開発者」で送信先を追加し、受け取るイベントを選びます。すべてのイベントは送信先の URL に JSON の POST で届きます。

ノートの本文は送信されません。本文が必要な場合は API キーで /notes/{id} を呼び出してください。プライベートページとその配下のものは送信されません。

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秒止まった時点でまとめて1回送信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 はタスク、ノート、コメントの ID です。

署名と再試行

すべてのリクエストには X-Event(イベント名)、X-Delivery-Id(本文の id と同じ)、X-Signature-256 が付きます。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 ?? ""));
}

15秒以内に 2xx を返してください。返さない場合は約10時間かけてさらに5回再試行します。20回続けて失敗すると送信先は自動で無効になり、オーナーと管理者に通知されます。

Free プランは送信先1つ、1時間あたり100回まで配信できます。Plus 以上は送信先10個、それぞれ1時間あたり1,000回まで配信できます。

受信 Webhook

他のシステムから、キーなしで1つの URL を通じて Tuhmo にデータを送れます。GitHub Actions、Zapier、フォームなどに便利です。URL は「設定」の「開発者」にある「受信 Webhook」で作成します(オーナーと管理者、Plus 以上)。

URL は作成した人として動作し、閲覧や変更ができる範囲もその人と同じです。URL は一度しか表示されず、知っている人は誰でもデータを送れます。漏れた場合は新しい URL を作成すると、古い URL はすぐに使えなくなります。

3種類の action のいずれかを指定して JSON の POST を送信します。受信 Webhook はお金に関する書類には触れず、クライアントに何かを送ることもできません。

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": "main のビルドが失敗", "dueDate": "2026-10-20"}'

成功すると、作成したものの id とともに 201 または 200 を返します。無効にした URL は 403 と code disabled を返します。URL ごとに1分あたり60リクエストまで、本文は256 KB までです。

すべてのリクエストは URL の履歴に14日間保存され、何をしたか、成功したか、どの IP から来たかを確認できます。

制限

キーごとに平均で毎秒3リクエスト、瞬間的には10まで、ワークスペース全体では毎秒10リクエストまでです。超えると 429 が返り、Retry-After ヘッダーに待つべき秒数が入ります。

リクエスト本文は1 MB までです。

エラー

エラーは JSON で返り、人が読むための error と、プログラムで分岐に使える code が含まれます。

ステータスcode意味
401unauthorizedキーがない、間違っている、期限切れ、または取り消されている
403read_only読み取り専用のキーでデータを変更しようとした
403planワークスペースのプランが対応していない(Free での書き込みなど)
403キーの所有者にワークスペースでその操作をする権限がない
403disabled受信 Webhook の URL が無効になっている
404not_foundパスが API に含まれていない、または対象が存在しない
413too_largeリクエスト本文が1 MB を超えている(受信 Webhook は256 KB)
429rate_limitedリクエストが多すぎる。Retry-After の秒数だけ待つ