开发者文档
TaskTask 对外提供三种接入方式:MCP(给 AI 助手用)、REST API v1(给脚本用)、Webhook(把事件推给你)。三条路径共用一个个人访问令牌。
60 秒上手
先选一条路径。三条路径都需要一个个人访问令牌(PAT)——创建一次,长期复用。
最快的第一次成功调用
复制下面这行,把 tt_pat_xxx 换成你的令牌,粘贴到终端即可看到你参与的项目列表:
curl -s -H "Authorization: Bearer tt_pat_xxx" \
https://tasktask.net/api/v1/projects
{"error":"..."},直接跳到 常见问题 对照排查。
认证与令牌
所有对外接口都用 Bearer 令牌 鉴权。令牌形如 tt_pat_ 开头,代表你的身份,权限由创建时勾选的作用域(scope)决定。
创建令牌
- 打开开发者设置 —— 登录后点右上角头像 → 开发者设置。
- 填名称、勾作用域、设有效期 —— 名称写清用途(如「我的 Claude」「同步脚本」),有效期填
0表示永不过期。 - 立即复制保存 —— 令牌只在创建时显示一次,关闭弹窗后无法再次查看。丢了只能吊销重建。
作用域
| 作用域 | 允许的操作 | 典型用途 |
|---|---|---|
projects:read | 列出项目、读项目详情、读成员 | 看板同步、报表统计 |
projects:write | 新建项目 | 项目初始化脚本 |
tasks:read | 读任务列表与详情 | 只读看板、周报生成 |
tasks:write | 新建 / 更新 / 删除任务 | 双向同步、AI 建任务 |
ai:use | 调用站内 AI 能力 | 自然语言建任务 |
最小权限原则:只读场景就别勾写入。令牌泄露时,你损失的范围由 scope 决定。
- 不要把令牌写进前端代码、公开仓库或截图。用环境变量:
TT_TOKEN=tt_pat_xxx。 - 一个令牌对应一个用途,泄露时只需吊销一个,不用牵连全部接入。
- 令牌可以随时在开发者设置里吊销,吊销后使用它的 MCP / 脚本立即失效。
REST API v1
基地址与鉴权
基地址:https://tasktask.net/api/v1
在每个请求头带上令牌:
Authorization: Bearer tt_pat_xxx Content-Type: application/json
接口列表
| 方法 | 路径 | 说明 | 所需作用域 |
|---|---|---|---|
| GET | /projects | 列出我参与的全部项目 | projects:read |
| POST | /projects | 新建项目(自动成为 owner) | projects:write |
| GET | /projects/:projectId | 项目详情 | projects:read |
| GET | /projects/:projectId/members | 项目成员列表 | projects:read |
| GET | /projects/:projectId/tasks | 任务列表(含依赖,不含回收站) | tasks:read |
| POST | /projects/:projectId/tasks | 在项目下新建任务 | tasks:write |
| GET | /tasks/:taskId | 任务详情(含依赖与评论) | tasks:read |
| PATCH | /tasks/:taskId | 更新任务字段(部分更新) | tasks:write |
| DELETE | /tasks/:taskId | 删除任务(级联子任务,进回收站) | tasks:write |
| GET | / | API 元信息(版本 / 作用域 / 接口清单) | — |
任务可写字段
请求示例
下面用「列出项目 → 在项目下建任务 → 更新任务状态」走一遍完整链路。切换语言看对应写法。
BASE=https://tasktask.net/api/v1
TOKEN=tt_pat_xxx
# 1. 列出项目
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/projects"
# 2. 在项目下新建任务
curl -s -X POST "$BASE/projects/p_xxx/tasks" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"task":"写发布说明","dueDate":"2026-09-30","priority":"high"}'
# 3. 更新任务状态
curl -s -X PATCH "$BASE/tasks/t_xxx" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status":"done"}'
import os, requests
BASE = "https://tasktask.net/api/v1"
HEAD = {"Authorization": "Bearer " + os.environ["TT_TOKEN"]}
# 1. 列出项目
projects = requests.get(f"{BASE}/projects", headers=HEAD).json()["projects"]
pid = projects[0]["id"]
# 2. 新建任务
task = requests.post(f"{BASE}/projects/{pid}/tasks", headers=HEAD, json={
"task": "写发布说明",
"dueDate": "2026-09-30",
"priority": "high",
}).json()["task"]
# 3. 更新状态
requests.patch(f"{BASE}/tasks/{task['id']}", headers=HEAD,
json={"status": "done"})
const BASE = 'https://tasktask.net/api/v1';
const HEAD = {
Authorization: 'Bearer ' + process.env.TT_TOKEN,
'Content-Type': 'application/json',
};
const call = (p, opt) =>
fetch(BASE + p, { headers: HEAD, ...opt }).then(r => r.json());
const { projects } = await call('/projects');
const { task } = await call(`/projects/${projects[0].id}/tasks`, {
method: 'POST',
body: JSON.stringify({ task: '写发布说明', priority: 'high' }),
});
await call('/tasks/' + task.id, {
method: 'PATCH',
body: JSON.stringify({ status: 'done' }),
});
响应示例:GET /projects
{
"projects": [
{
"id": "p_a1b2c3",
"name": "XeFrame 硬件项目",
"ownerId": "u_xxx",
"ungroupedLabel": "未分组",
"autoRollup": 1,
"createdAt": "2026-09-01T09:12:00.000Z"
}
]
}
响应示例:POST /projects/:projectId/tasks(201)
{
"task": {
"id": "t_mu10agvmj3e5t6",
"projectId": "p_a1b2c3",
"task": "写发布说明",
"status": "not_started",
"priority": "normal",
"startDate": "",
"dueDate": "",
"parentId": "",
"isMilestone": 0,
"sortOrder": 3000,
"lastUpdated": "2026-09-14T13:20:41.000Z"
}
}
错误码与限流
| 状态码 | 含义 | 怎么处理 |
|---|---|---|
400 | 参数无效(如任务标题为空) | 检查 body 必填项 |
401 | 令牌缺失 / 无效 / 已吊销 / 已过期 | 重新签发令牌;确认请求头是 Bearer |
403 | scope 不足,或你不是该项目成员 | 补勾作用域重建令牌,或先把账号加入项目 |
404 | 资源不存在 | 确认 ID 拼写;已删除的任务查不到 |
429 | 触发限流 | 降低频率,等窗口重置(见下) |
在线调试(Try-It)
不用打开终端,直接在这里发真实请求。令牌只存在你的浏览器内存里,不会被服务端记录。
Webhook
不需要轮询。任务或项目发生变化时,TaskTask 主动把事件 POST 到你的地址。
工作原理
- 事件发生 —— 例如有人新建了任务,系统产生
task.created事件。 - 排队投递 —— 系统把事件写进投递队列,异步 POST 到你的 URL(超时 15 秒)。
- 你返回 2xx —— 只要状态码是 2xx 即视为成功;其它状态码或超时会按退避重试。
请求头
| Header | 说明 |
|---|---|
X-TaskTask-Event | 事件类型,如 task.created |
X-TaskTask-Delivery | 本次投递的唯一 ID,用它做幂等去重 |
X-TaskTask-Timestamp | Unix 秒级时间戳,参与签名 |
X-TaskTask-Signature | HMAC-SHA256 十六进制签名 |
User-Agent | TaskTask-Webhook/1.0 |
事件类型
| 事件 | 触发时机 |
|---|---|
task.created | 新建任务成功后 |
task.updated | 任务字段被修改后 |
task.completed | 任务状态变为已完成 |
task.deleted | 任务被删除(含级联子任务) |
task.restored | 任务从回收站恢复 |
project.created | 新建项目后 |
project.updated | 项目信息被修改后 |
project.member.joined | 成员加入项目 |
project.member.left | 成员离开或被移出项目 |
Payload 示例
请求体是 JSON,除业务字段外固定带 event / emittedAt / version 三个元字段。
task.created
{
"event": "task.created",
"emittedAt": "2026-09-14T13:20:41.000Z",
"version": "2024-09-14",
"task": {
"id": "t_mu10agvmj3e5t6",
"task": "写发布说明",
"status": "not_started"
},
"project": {
"id": "p_a1b2c3",
"name": "XeFrame 硬件项目"
}
}
project.member.joined
{
"event": "project.member.joined",
"emittedAt": "2026-09-14T13:22:10.000Z",
"version": "2024-09-14",
"project": { "id": "p_a1b2c3", "name": "XeFrame 硬件项目" },
"member": { "id": "u_xxx", "name": "Mike", "role": "member" }
}
测试事件
在开发者设置里点「测试」会发一条带 "test": true 的 task.created,用于验证链路通不通:
{
"test": true,
"event": "task.created",
"emittedAt": "2026-09-14T13:25:00.000Z",
"version": "2024-09-14",
"task": { "id": "test_task", "task": "测试任务", "status": "not_started" },
"project": { "id": "test_project", "name": "测试项目" }
}
签名校验
签名算法:HMAC-SHA256(secret, timestamp + "." + 原始请求体),十六进制输出。
其中 secret 是创建订阅时返回的 tt_whs_ 密钥,只显示一次。
const crypto = require('crypto');
const express = require('express');
const app = express();
// 关键:必须拿"原始请求体"验签,不能先 JSON.parse
app.post('/tasktask-webhook',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.get('X-TaskTask-Signature') || '';
const ts = req.get('X-TaskTask-Timestamp') || '';
const raw = req.body.toString('utf8');
const expected = crypto.createHmac('sha256', process.env.TT_WEBHOOK_SECRET)
.update(ts + '.' + raw)
.digest('hex');
const ok = sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
if (!ok) return res.status(401).end();
// 先应答,再处理,避免对方超时
res.status(200).end();
const payload = JSON.parse(raw);
const deliveryId = req.get('X-TaskTask-Delivery');
handleEvent(payload, deliveryId); // 用 deliveryId 做幂等
});
import hmac, hashlib
from flask import Flask, request
app = Flask(__name__)
SECRET = b"tt_whs_xxx"
@app.post("/tasktask-webhook")
def hook():
sig = request.headers.get("X-TaskTask-Signature", "")
ts = request.headers.get("X-TaskTask-Timestamp", "")
raw = request.get_data() # 原始字节,不要用 request.json
expected = hmac.new(
SECRET, (ts + ".").encode() + raw, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, sig):
return "", 401
payload = request.get_json()
handle_event(payload, request.headers.get("X-TaskTask-Delivery"))
return "", 200
JSON.parse 再 JSON.stringify 验证。
重新序列化会改变键顺序和空格,签名必然对不上。一定要用接收到的原始 body 字节参与计算。
X-TaskTask-Timestamp 与当前时间的差值,超过 5 分钟直接丢弃,可防重放。
重试与投递日志
对方未返回 2xx 或超时(15 秒)即视为失败,系统按下表退避重试,最多 5 次尝试(首次 + 4 次重试):
| 第几次尝试 | 相对上次的间隔 | 累计耗时 |
|---|---|---|
| 第 1 次(首次) | 立即 | 0s |
| 第 2 次 | 5s | 5s |
| 第 3 次 | 10s | 15s |
| 第 4 次 | 15s | 30s |
| 第 5 次 | 20s | 50s |
| 全部失败 | 标记为 failed,不再重试 | — |
每一次投递(含失败)都会记入投递日志,在开发者设置 → Webhook 订阅 → 投递日志里可以看到事件类型、状态、响应码与错误信息。
- 先返回 2xx,再处理业务 —— 处理耗时超过 15 秒会被判定超时并触发重试。
- 用
X-TaskTask-Delivery做幂等 —— 网络抖动可能导致重复投递,按投递 ID 去重最稳妥。 - 本地开发用内网穿透 —— Webhook 需要公网可达地址;本地调试可先点「测试」按钮验证。
- 不要用 2xx 之外的码表达业务错误 —— 返回 4xx/5xx 会被当成投递失败并重试。
MCP 接入
把 TaskTask 作为 MCP Server 挂到 AI 客户端(Claude Desktop、Cursor、Cherry Studio 等),让助手直接读写你的任务。
服务地址:https://tasktask.net/mcp(HTTP 传输,用 PAT 做 Bearer 鉴权)
客户端配置
{
"mcpServers": {
"tasktask": {
"type": "http",
"url": "https://tasktask.net/mcp",
"headers": {
"Authorization": "Bearer tt_pat_xxx"
}
}
}
}
可用工具
| 工具 | 作用 | 所需作用域 |
|---|---|---|
tasktask_list_projects | 列出我参与的全部项目(含角色) | projects:read |
tasktask_list_tasks | 列出指定项目下的任务 | tasks:read |
tasktask_get_task | 获取单个任务详情 | tasks:read |
tasktask_create_task | 在项目下新建任务 | tasks:write |
tasktask_update_task | 更新任务字段 | tasks:write |
验证是否接通
- 重启 AI 客户端,确认工具列表里出现
tasktask_*五个工具。 - 输入「用 tasktask 列出我的项目」,应返回你的真实项目列表。
- 若报鉴权错误,回到认证与令牌确认令牌未吊销、未过期、scope 足够。
常见问题
- 请求头格式必须是
Authorization: Bearer tt_pat_xxx,Bearer后有且仅有一个空格。 - 令牌是否已被吊销或已过期?去开发者设置看状态。
- 是否误把 MCP 的配置片段当成 REST 令牌用了?两者是同一个 PAT,但不要漏掉前缀
tt_pat_。
tasks:write 的。
② 你不是该项目成员——令牌权限会继承你本人的项目权限,先让 owner 把你加进项目。
- 先在开发者设置点订阅的「测试」按钮——能收到说明链路通,收不到说明是网络/地址问题。
- URL 必须公网可达,且是
http或https;localhost收不到。 - 订阅是否处于「启用中」?停用状态不会投递。
- 看投递日志:有记录但状态是
failed,说明对方返回了非 2xx,看错误详情。
变更日志
接口有破坏性变更时会在此登记,并给出迁移指引。