Dida365 滴答清单 (Open API)

v1.0.0

滴答清单 (Dida365) API 集成,支持自建 OAuth 认证。管理任务和项目。 当用户想要在滴答清单中创建、更新、完成或组织任务和项目时使用此 Skill。 需要用户在 developer.dida365.com 创建应用并配置 DIDA365_CLIENT_ID、DIDA365_CLIENT_SECR...

1· 136·0 current·0 all-time

Install

OpenClaw Prompt Flow

Install with OpenClaw

Best for remote or guided setup. Copy the exact prompt, then paste it into OpenClaw for imchongliu/dida365-api.

Previewing Install & Setup.
Prompt PreviewInstall & Setup
Install the skill "Dida365 滴答清单 (Open API)" (imchongliu/dida365-api) from ClawHub.
Skill page: https://clawhub.ai/imchongliu/dida365-api
Keep the work scoped to this skill only.
After install, inspect the skill metadata and help me finish setup.
Required env vars: DIDA365_CLIENT_ID, DIDA365_CLIENT_SECRET
Use only the metadata you can verify from ClawHub; do not invent missing requirements.
Ask before making any broader environment changes.

Command Line

CLI Commands

Use the direct CLI path if you want to install manually and keep every step visible.

OpenClaw CLI

Bare skill slug

openclaw skills install dida365-api

ClawHub CLI

Package manager switcher

npx clawhub@latest install dida365-api
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description match the required environment variables (DIDA365_CLIENT_ID, DIDA365_CLIENT_SECRET) and the SKILL.md exclusively documents OAuth + API calls to dida365 endpoints — the requested secrets are exactly what an OAuth integration needs.
Instruction Scope
Instructions are limited to: creating a developer app, running a local temporary HTTP listener for OAuth callback, exchanging code for an access token, saving the token to ~/.config/dida365/token, and making API requests with that token. They do not ask to read unrelated system files, other credentials, or to exfiltrate data to third-party endpoints.
Install Mechanism
No install spec or external downloads — this is instruction-only. Nothing will be written to disk by an installer beyond the token file the script itself creates under the user's home directory.
Credentials
Only DIDA365_CLIENT_ID and DIDA365_CLIENT_SECRET are required, which are proportionate for an OAuth integration. The skill also stores an access token in ~/.config/dida365/token (documented) — expected for this workflow.
Persistence & Privilege
always:false and default autonomous invocation are used (normal). The skill does not request system-wide config changes or access to other skills' settings; it only writes/reads its own token file.
Assessment
This skill is internally consistent for integrating with Dida365, but take these practical precautions before installing: 1) Only provide DIDA365_CLIENT_ID and DIDA365_CLIENT_SECRET if you trust the skill source — this package has no homepage/source URL in the metadata. 2) The OAuth flow stores a long-lived access token (~180 days) at ~/.config/dida365/token; protect that file (permissions are set to 600 in the example) and do not commit it to version control. 3) Because there is no refresh token, you will need to re-authorize when the token expires. 4) The runtime instructions will cause the agent (or you running the snippet) to open a browser and start a local listener on 127.0.0.1:36500 — ensure that port/redirect URI are acceptable for you. 5) Avoid pasting client secrets or access tokens into third-party chats; if you are unsure of the registry publisher (owner ID present but no homepage), consider manually following the SKILL.md steps yourself rather than granting the agent autonomous access. If you want higher assurance, request a skill package with a verifiable source or an install spec from an official repository.

Like a lobster shell, security has layers — review code before you run it.

Runtime requirements

Clawdis
EnvDIDA365_CLIENT_ID, DIDA365_CLIENT_SECRET
latestvk974kxd2ktpf5tgcaxygz1dmrn83rsz6
136downloads
1stars
1versions
Updated 1mo ago
v1.0.0
MIT-0

Dida365 滴答清单

通过 Dida365 官方 OAuth 认证访问滴答清单 API,支持任务和项目的完整 CRUD 操作。

前置准备

1. 创建 Dida365 开发者应用

  1. 登录 developer.dida365.com
  2. 点击「创建应用」
  3. 填写应用名称(任意)
  4. 在「回调地址 (Redirect URI)」中添加:http://127.0.0.1:36500/callback
  5. 创建完成后,记录下 Client IDClient Secret

2. 配置环境变量

export DIDA365_CLIENT_ID="YOUR_CLIENT_ID"
export DIDA365_CLIENT_SECRET="YOUR_CLIENT_SECRET"

建议将上述配置写入 ~/.bashrc~/.zshrc.env 文件。

获取 Access Token

首次使用需要通过 OAuth 授权获取 Access Token。以下流程会启动一个临时本地服务来接收回调。

一键获取 Token(Python)

python3 << 'PYEOF'
import os, json, http.server, urllib.parse, urllib.request, threading, webbrowser

CLIENT_ID = os.environ["DIDA365_CLIENT_ID"]
CLIENT_SECRET = os.environ["DIDA365_CLIENT_SECRET"]
REDIRECT_URI = "http://127.0.0.1:36500/callback"
TOKEN_FILE = os.path.expanduser("~/.config/dida365/token")
code_holder = {}

class Handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        params = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
        if "code" in params:
            code_holder["code"] = params["code"][0]
            self.send_response(200)
            self.end_headers()
            self.wfile.write(b"Authorization successful! You can close this tab.")
        else:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b"Missing code parameter.")
    def log_message(self, *args): pass

server = http.server.HTTPServer(("127.0.0.1", 36500), Handler)
thread = threading.Thread(target=server.handle_request)
thread.start()

auth_url = (
    f"https://dida365.com/oauth/authorize"
    f"?client_id={CLIENT_ID}"
    f"&scope=tasks%3Aread+tasks%3Awrite"
    f"&state=random_state_string"
    f"&redirect_uri={urllib.parse.quote(REDIRECT_URI, safe='')}"
    f"&response_type=code"
)
print(f"请在浏览器中打开以下链接并点击授权:\n\n{auth_url}\n")
webbrowser.open(auth_url)

thread.join(timeout=120)
server.server_close()

if "code" not in code_holder:
    print("❌ 超时:未收到授权码,请重试。")
    exit(1)

code = code_holder["code"]
print(f"✅ 已获取授权码,正在交换 Token...")

data = urllib.parse.urlencode({
    "client_id": CLIENT_ID,
    "client_secret": CLIENT_SECRET,
    "code": code,
    "grant_type": "authorization_code",
    "redirect_uri": REDIRECT_URI,
}).encode()

req = urllib.request.Request(
    "https://dida365.com/oauth/token",
    data=data,
    method="POST"
)
req.add_header("Content-Type", "application/x-www-form-urlencoded")
resp = json.load(urllib.request.urlopen(req))
token = resp["access_token"]

os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True)
with open(TOKEN_FILE, "w") as f:
    json.dump({"access_token": token}, f)
os.chmod(TOKEN_FILE, 0o600)

print(f"✅ Token 已保存到 {TOKEN_FILE}")
print(f"   有效期约 180 天,请注意及时重新授权。")
PYEOF

Token 存储

Token 保存在 ~/.config/dida365/token,格式:

{
  "access_token": "your_access_token_here"
}

⚠️ 重要提示:

  • Token 有效期约 180 天
  • 滴答清单当前 API 没有 refresh_token 机制
  • Token 过期后需重新执行上述授权流程
  • 请妥善保管 Token 文件,不要提交到版本控制系统

Base URL

https://api.dida365.com/open/v1/

认证

所有请求需要在 Authorization 头中携带 Access Token:

Authorization: Bearer {ACCESS_TOKEN}

快速测试

# 读取 Token 并列出项目
python3 << 'PYEOF'
import os, json, urllib.request

token_file = os.path.expanduser("~/.config/dida365/token")
with open(token_file) as f:
    token = json.load(f)["access_token"]

req = urllib.request.Request("https://api.dida365.com/open/v1/project")
req.add_header("Authorization", f"Bearer {token}")
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2, ensure_ascii=False))
PYEOF

API 参考

项目操作

列出所有项目

GET /open/v1/project

响应示例:

[
  {
    "id": "6984773291819e6d58b746a8",
    "name": "📝 收集箱",
    "sortOrder": 0,
    "viewMode": "list",
    "kind": "TASK"
  },
  {
    "id": "6984773291819e6d58b746a9",
    "name": "🏠 个人",
    "sortOrder": -1099511627776,
    "viewMode": "list",
    "kind": "TASK"
  }
]

获取项目及任务

GET /open/v1/project/{projectId}/data

响应示例:

{
  "project": {
    "id": "69847732b8e5e969f70e7460",
    "name": "📋 工作",
    "sortOrder": -3298534883328,
    "viewMode": "list",
    "kind": "TASK"
  },
  "tasks": [
    {
      "id": "69847732b8e5e969f70e7464",
      "projectId": "69847732b8e5e969f70e7460",
      "title": "完成报告",
      "content": "季度总结报告",
      "priority": 0,
      "status": 0,
      "tags": [],
      "isAllDay": false
    }
  ],
  "columns": [
    {
      "id": "69847732b8e5e969f70e7463",
      "projectId": "69847732b8e5e969f70e7460",
      "name": "待办",
      "sortOrder": -2199023255552
    }
  ]
}

创建项目

POST /open/v1/project
Content-Type: application/json

{
  "name": "我的新项目",
  "viewMode": "list"
}

响应示例:

{
  "id": "69870cbe8f08b4a6770a38d3",
  "name": "我的新项目",
  "sortOrder": 0,
  "viewMode": "list",
  "kind": "TASK"
}

viewMode 选项:

  • list - 列表视图
  • kanban - 看板视图
  • timeline - 时间线视图

删除项目

DELETE /open/v1/project/{projectId}

成功时返回空响应(状态码 200)。

任务操作

获取任务

GET /open/v1/project/{projectId}/task/{taskId}

响应示例:

{
  "id": "69847732b8e5e969f70e7464",
  "projectId": "69847732b8e5e969f70e7460",
  "sortOrder": -1099511627776,
  "title": "任务标题",
  "content": "任务描述/备注",
  "timeZone": "Asia/Shanghai",
  "isAllDay": true,
  "priority": 0,
  "status": 0,
  "tags": [],
  "columnId": "69847732b8e5e969f70e7461",
  "etag": "2sayfdsh",
  "kind": "TEXT"
}

创建任务

POST /open/v1/task
Content-Type: application/json

{
  "title": "新任务",
  "projectId": "6984773291819e6d58b746a8",
  "content": "任务描述",
  "priority": 0,
  "dueDate": "2026-03-15T10:00:00+0000",
  "isAllDay": false
}

响应示例:

{
  "id": "69870cb08f08b86b38951175",
  "projectId": "6984773291819e6d58b746a8",
  "sortOrder": -1099511627776,
  "title": "新任务",
  "timeZone": "Asia/Shanghai",
  "isAllDay": false,
  "priority": 0,
  "status": 0,
  "tags": [],
  "etag": "gl7ibhor",
  "kind": "TEXT"
}

优先级值:

  • 0 - 无
  • 1 - 低
  • 3 - 中
  • 5 - 高

更新任务

POST /open/v1/task/{id}
Content-Type: application/json

{
  "id": "69870cb08f08b86b38951175",
  "projectId": "6984773291819e6d58b746a8",
  "title": "更新后的任务标题",
  "priority": 1
}

响应示例:

{
  "id": "69870cb08f08b86b38951175",
  "projectId": "6984773291819e6d58b746a8",
  "title": "更新后的任务标题",
  "priority": 1,
  "status": 0,
  "etag": "hmb7uk8c",
  "kind": "TEXT"
}

完成任务

POST /open/v1/project/{projectId}/task/{taskId}/complete

成功时返回空响应(状态码 200)。

删除任务

DELETE /open/v1/project/{projectId}/task/{taskId}

成功时返回空响应(状态码 200)。

任务字段说明

字段类型说明
idstring任务 ID
projectIdstring所属项目 ID
titlestring任务标题
contentstring任务描述/备注(支持 Markdown)
priorityinteger优先级:0=无, 1=低, 3=中, 5=高
statusinteger状态:0=进行中, 2=已完成
dueDatestring截止日期(ISO 8601 格式)
startDatestring开始日期(ISO 8601 格式)
isAllDayboolean是否全天任务
timeZonestring时区(如 "Asia/Shanghai")
tagsarray标签列表
columnIdstring看板列 ID(看板视图时使用)
sortOrdernumber项目内的排序
kindstring任务类型:"TEXT"、"CHECKLIST"

代码示例

Python(requests)

import os, json

# 读取 Token
with open(os.path.expanduser("~/.config/dida365/token")) as f:
    token = json.load(f)["access_token"]

headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
}

# 列出所有项目
import requests
resp = requests.get("https://api.dida365.com/open/v1/project", headers=headers)
projects = resp.json()
print(json.dumps(projects, indent=2, ensure_ascii=False))

# 创建任务
resp = requests.post("https://api.dida365.com/open/v1/task", headers=headers, json={
    "title": "新任务",
    "projectId": "YOUR_PROJECT_ID",
    "content": "通过 API 创建的任务",
    "priority": 3,
    "dueDate": "2026-04-01T09:00:00+0800"
})
print(resp.json())

# 完成任务
resp = requests.post(
    "https://api.dida365.com/open/v1/project/YOUR_PROJECT_ID/task/TASK_ID/complete",
    headers=headers
)
print(f"状态: {resp.status_code}")

JavaScript(fetch)

import { readFileSync } from "fs";

// 读取 Token
const { access_token: token } = JSON.parse(
  readFileSync(process.env.HOME + "/.config/dida365/token", "utf-8")
);

const headers = {
  Authorization: `Bearer ${token}`,
  "Content-Type": "application/json",
};

// 列出所有项目
const projects = await fetch("https://api.dida365.com/open/v1/project", {
  headers,
}).then((r) => r.json());
console.log(projects);

// 创建任务
const task = await fetch("https://api.dida365.com/open/v1/task", {
  method: "POST",
  headers,
  body: JSON.stringify({
    title: "新任务",
    projectId: "YOUR_PROJECT_ID",
    content: "通过 API 创建的任务",
    priority: 3,
  }),
}).then((r) => r.json());
console.log(task);

// 完成任务
await fetch(
  `https://api.dida365.com/open/v1/project/YOUR_PROJECT_ID/task/TASK_ID/complete`,
  { method: "POST", headers }
);

curl 示例

# 读取 Token
TOKEN=$(cat ~/.config/dida365/token | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# 列出项目
curl -s -H "Authorization: Bearer $TOKEN" https://api.dida365.com/open/v1/project | python3 -m json.tool

# 创建任务
curl -s -X POST https://api.dida365.com/open/v1/task \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"测试任务","projectId":"YOUR_PROJECT_ID"}' | python3 -m json.tool

注意事项

  • Open API 仅提供任务和项目的访问
  • 习惯、专注/番茄钟等功能不通过 Open API 提供
  • 任务 status 值:0 = 进行中,2 = 已完成
  • 优先级值:0 = 无,1 = 低,3 = 中,5 = 高
  • 日期使用 ISO 8601 格式带时区偏移(如 2026-03-15T10:00:00+0800
  • 项目的 viewMode 选项:listkanbantimeline
  • columns 字段用于看板视图的列定义
  • Token 有效期约 180 天,无 refresh_token,过期需重新授权

错误处理

状态码含义处理方式
400请求参数错误检查请求体格式和必填字段
401Token 无效或已过期重新执行 OAuth 授权流程获取新 Token
404资源未找到确认项目 ID / 任务 ID 是否正确
429请求频率超限降低请求频率,等待后重试
5xx服务端错误稍后重试

故障排除

Token 过期(401 错误):

# 重新运行授权脚本获取新 Token
# 参考上方「获取 Access Token」章节

检查 Token 有效性:

TOKEN=$(cat ~/.config/dida365/token | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" https://api.dida365.com/open/v1/project
# 返回 200 表示有效,返回 401 表示已过期

环境变量未设置:

echo $DIDA365_CLIENT_ID
echo $DIDA365_CLIENT_SECRET

资源

Comments

Loading comments...