Leantime 3.12.0 常用 API 与运维命令详解
Leantime 3.12.0 常用 API 与运维命令详解:/api/jsonrpc 方法命名与 @api 白名单、三种认证与 CLI 签发 Bearer Token、项目/任务/评论/工时/搜索链路实测、错误码表与备份恢复运维命令。
Leantime 3.12.0 常用 API 与运维命令详解
目标:把 Leantime 3.12.0 的两个「自动化入口」讲透——
/api/jsonrpc的 JSON-RPC 2.0 接口怎么认证、怎么调、错误码怎么读,以及php bin/leantime与数据库备份恢复等日常运维命令。本文全部请求、响应与回显于 2026-10-28 在 Ubuntu 22.04.5 LTS + Leantime 3.12.0 + PHP 8.3.36 + MariaDB 10.11.19 的服务上实测照抄。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| Leantime | 3.12.0 |
| PHP | 8.3.36 |
| 数据库 | MariaDB 10.11.19(库名 leantime,用户 leantime) |
| 应用目录 | /var/www/leantime |
| 接口地址 | http://192.168.1.71:8141/api/jsonrpc |
| 演示账号 | admin@example.com / Admin@q1w2e3r4 |
二、接口形态与命名规则
Leantime 只暴露一个 API 端点:/api/jsonrpc。它不是 REST,而是 JSON-RPC 2.0,所有业务能力都通过「方法名 + 参数对象」调用。
2.1 方法名格式
leantime.rpc.{module}.{service}.{method}
例如 leantime.rpc.Tickets.getTicket。四段式写法(leantime.rpc.Tickets.getTicket)也可以,此时 module 与 service 同名。解析规则是大小写敏感的:Tickets 不能写成 tickets。
进入分发前有三道校验,任一不过都返回 -32601:
- 服务类是否存在(
Domain\{Module}\Services\{Service}、插件同名路径); - 方法是否存在;
- 方法是否带
@api注释——没有@api的方法一律不可远程调用。
实测一个没有 @api 的方法:
curl -s -X POST http://192.168.1.71:8141/api/jsonrpc \
-H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \
-d '{"jsonrpc":"2.0","method":"leantime.rpc.Tickets.prepareTicketDates","params":{},"id":23}'
{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found","data":"Method is not available via API: prepareTicketDates"},"id":23}
data 里明确写了「is not available via API」,与「方法不存在」区分:(不存在的写 Method doesn't exist: xxx)。排障时看这一句就能判断是拼错还是没开放。
2.2 传输约束
- 只支持
POST与GET;PATCH/DELETE返回-32600,提示只支持 POST/GET; jsonrpc字段必须存在且等于"2.0",否则-32600;- 请求体是 JSON 对象即单次调用,是 JSON 数组即批量调用;
params可以是对象,也可以是「JSON 字符串」——服务端会二次解码,方便老客户端传字符串。
三、认证:三种方式
| 方式 | 适用场景 | 传递方式 |
|---|---|---|
| 会话 Cookie | 前端页面自身调用 | 浏览器 session |
| API Key | 脚本/第三方集成 | 请求头 x-api-key: <key> |
| Bearer Token | 自动化任务、CI | 请求头 Authorization: Bearer <token> |
三者都走同一个认证中间件,认证通过后按该用户身份执行;API Key 在数据库里是一条 source='api' 的用户记录,所以它的权限就是创建时选的角色。
3.1 无凭据的响应
curl -s -i -X POST http://192.168.1.71:8141/api/jsonrpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"leantime.rpc.Api.Config.getSystemInfo","params":{},"id":1}'
实测:
HTTP/1.1 401 Unauthorized
{"error":"Unauthorized"}
注意 401 的响应体不是 JSON-RPC 错误对象,客户端要按 HTTP 状态码先分支。
3.2 用 CLI 签发 Bearer Token(实测最省事)
3.12.0 自带 auth:create-bearer-token,不需要任何插件:
cd /var/www/leantime
php bin/leantime auth:create-bearer-token --email=admin@example.com --name=doc-d5 --quiet-output
实测回显(仅输出 token 本体,便于 $(...) 捕获):
NFs0u8wB685EglWBLO4TpSczYMsSR1ICEs9a1umu
随后即可调用:
curl -s -X POST http://192.168.1.71:8141/api/jsonrpc \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer NFs0u8wB685EglWBLO4TpSczYMsSR1ICEs9a1umu' \
-d '{"jsonrpc":"2.0","method":"leantime.rpc.Api.Config.getSystemInfo","params":{},"id":1}'
{"jsonrpc":"2.0","result":{"version":"3.12.0","enabledPlugins":[]},"id":1}
--name 会记在 token 行上,用于审计「这个 token 是给谁用的」。token 一旦泄露就是管理员权限,用完应到数据库删除对应行或换发。
3.3 认证失败也会限流
用错误密钥连续请求,超过 LEAN_RATELIMIT_AUTH(默认 20,实例里被调成 2)后返回:
HTTP/1.1 429 Too Many Requests
{"error":"Too many failed authentication attempts. Try again later."}
窗口按「IP + 1 分钟」滚动,期间换成正确 token 也会被拒。自动化脚本必须在首次 401 就停止重试,而不是循环刷新。
四、系统与能力探测
| 方法 | 参数 | 用途 |
|---|---|---|
Api.Config.getSystemInfo | 无 | 版本号 + 已启用插件,最适合做健康检查 |
Users.getAll | activeOnly(可选) | 拉用户清单,核对权限与账号状态 |
Users.getUserByEmail | email | 按邮箱定位用户 ID |
Projects.getAllProjects | 无 | 全部项目(不含权限过滤,管理员视角) |
Users.getAll 实测(截取前两条):
{"jsonrpc":"2.0","result":[
{"id":1,"lastname":"","role":"50","status":"A","username":"admin@example.com","twoFAEnabled":0,"jobTitle":"DevOps Engineer","firstname":"admin"},
{"id":3,"lastname":"Lee","role":"30","status":"A","username":"ops@example.com","twoFAEnabled":0,"clientName":"quzuo","firstname":"Ops"}
],"id":3}
role 是数字字符串:50 为所有者、40 管理员、30 经理、20 成员、10 只读。判断「谁能改配置」时看这个字段,不要看 jobTitle。
五、项目与任务链路
5.1 项目
{"jsonrpc":"2.0","method":"leantime.rpc.Projects.getAllProjects","params":{},"id":2}
{"jsonrpc":"2.0","result":[
{"id":1,"name":"My Project","clientId":null,"hourBudget":"0","type":"project","modified":"2026-10-27 15:28:12"},
{"id":2,"name":"API 演示项目","clientId":1,"clientName":"quzuo","type":"project","modified":"2026-10-27 16:19:21"}
],"id":2}
单项目用 Projects.getProject(参数 id),返回体里多出 details、psettings(restricted 表示仅项目成员可见)、isFavorite。
5.2 建任务:addTicket 返回新 ID
{"jsonrpc":"2.0","method":"leantime.rpc.Tickets.addTicket","params":{"values":{
"headline":"D5 实测任务:JSON-RPC 创建","description":"由 API 命令篇实测创建",
"projectId":2,"type":"task","status":3,"userId":1,"editorId":1,"priority":3}},"id":5}
实测回显:
{"jsonrpc":"2.0","result":12,"id":5}
result 直接是新任务 ID(标量,不是数组)。status 取值来自状态标签接口,3 通常对应 New。
5.3 读任务:getAll 与 getTicket
按项目 + 未完成筛选:
{"jsonrpc":"2.0","method":"leantime.rpc.Tickets.getAll","params":{"searchCriteria":{"projectId":2,"status":"not_done"}},"id":4}
返回是任务对象数组,关键字段:id、headline、projectId、status、priority、editorId、milestoneid、dateToFinish、sprint。注意 dateToFinish 在未设置时是 0000-00-00 00:00:00,脚本里必须判空而不是直接格式化。
单条用 Tickets.getTicket(参数 id),返回体包含 projectName、clientName、authorFirstname 等联表字段,适合做详情页。
5.4 改任务:patchTicket
{"jsonrpc":"2.0","method":"leantime.rpc.Tickets.patchTicket",
"params":{"id":12,"values":{"headline":"D5 实测任务:已改名","status":0}},"id":7}
{"jsonrpc":"2.0","result":true,"id":7}
patchTicket 是部分更新:只传要改的字段,未传的保持原值。再次 getTicket 验证,headline 已变为 D5 实测任务:已改名。若需要整对象覆盖用 updateTicket,两者对必填字段的严格要求不同,跨版本升级时优先用 patchTicket。
5.5 状态标签
{"jsonrpc":"2.0","method":"leantime.rpc.Tickets.getStatusLabels","params":{"projectId":2},"id":62}
{"jsonrpc":"2.0","result":{
"3":{"name":"New","class":"label-info","statusType":"NEW","kanbanCol":true,"sortKey":1},
"1":{"name":"Blocked","class":"label-important","statusType":"INPROGRESS","kanbanCol":true,"sortKey":2},
"4":{"name":"In Progress","class":"label-warning","statusType":"INPROGRESS"}
},"id":62}
statusType 只有三档(NEW/INPROGRESS/DONE),看板的列与「完成率」统计都按它归类,自定义状态名不会改变统计口径。
六、协作数据:评论、工时、迭代、标签
6.1 评论
{"jsonrpc":"2.0","method":"leantime.rpc.Comments.addComment",
"params":{"values":{"text":"API 实测评论:链路打通"},"module":"ticket","entityId":12},"id":8}
{"jsonrpc":"2.0","result":true,"id":8}
读取:
{"jsonrpc":"2.0","method":"leantime.rpc.Comments.getComments","params":{"module":"ticket","entityId":12},"id":9}
{"jsonrpc":"2.0","result":[{"id":1,"text":"API 实测评论:链路打通","date":"2026-10-27 17:01:13","moduleId":12,"userId":1,"commentParent":0,"firstname":"admin","lastname":""}],"id":9}
module 支持 ticket、project、article、idea、{type}canvasitem,复数形式(tickets)也认。评论对象不存在时抛 NotFoundException,返回 -32001 一类业务错误码。
6.2 工时
{"jsonrpc":"2.0","method":"leantime.rpc.Timesheets.logTime",
"params":{"ticketId":12,"params":{"hours":1.5,"kind":"GENERAL","date":"2026-10-28","description":"API 登记工时"}},"id":10}
{"jsonrpc":"2.0","result":true,"id":10}
汇总校验:
{"jsonrpc":"2.0","method":"leantime.rpc.Timesheets.getSumLoggedHoursForTicket","params":{"ticketId":12},"id":61}
{"jsonrpc":"2.0","result":1.5,"id":61}
logTime 是累加语义(同名日期多次调用会叠加),要覆盖某天工时用 upsertTime。kind 必须是 Timesheets.getLoggableHourTypes 返回的可记账类型之一,传未定义值会被拒绝。
6.3 迭代与标签
{"jsonrpc":"2.0","method":"leantime.rpc.Sprints.getAllSprints","params":{"projectId":2},"id":12}
{"jsonrpc":"2.0","result":[],"id":12}
该演示项目未建迭代,返回空数组——这是正常值,不要按「接口失败」处理。
{"jsonrpc":"2.0","method":"leantime.rpc.Tags.getTags","params":{"projectId":2,"term":"api"},"id":13}
{"jsonrpc":"2.0","result":[],"id":13}
Tags.getTags 是前缀检索(term 是输入中的词干),用于做标签自动补全;项目里没有匹配标签时同样返回空数组。
七、全局搜索
{"jsonrpc":"2.0","method":"leantime.rpc.Search.quickSearch","params":{"term":"API","perType":2},"id":14}
实测(节选):
{"jsonrpc":"2.0","result":{
"tickets":[
{"type":"tickets","id":10,"title":"API 创建任务示例","snippet":"通过 JSON-RPC 创建","projectName":"My Project","modalPath":"/tickets/showTicket/10"},
{"type":"tickets","id":12,"title":"D5 实测任务:已改名","snippet":"由 API 命令篇实测创建","projectName":"API 演示项目","modalPath":"/tickets/showTicket/12"}
],
"projects":[{"type":"projects","id":2,"title":"API 演示项目","snippet":"由 JSON-RPC 创建"}]
},"id":14}
返回按类型分组,perType 控制每类条数。modalPath 是前端可直接打开的详情路径,做「搜索跳转」时用它比拼接 URL 可靠。需要分页与过滤时换用 Search.search(参数 term、type、limit、offset、filters)。
八、批量调用与 GET 调用
8.1 批量
请求体为数组时,服务端逐个执行并按顺序返回数组,单个子请求失败不影响其他子请求:
[
{"jsonrpc":"2.0","method":"leantime.rpc.Api.Config.getSystemInfo","params":{},"id":31},
{"jsonrpc":"2.0","method":"leantime.rpc.Projects.getAllProjects","params":{},"id":32}
]
实测回显(完整):
[
{"jsonrpc":"2.0","result":{"version":"3.12.0","enabledPlugins":[]},"id":31},
{"jsonrpc":"2.0","result":[{"id":1,"name":"My Project","clientId":null,"hourBudget":"0","dollarBudget":0,"state":null,"menuType":"","type":"project","modified":"2026-10-27 15:28:12","clientName":null,"start":null,"end":null,"status":null},{"id":2,"name":"API 演示项目","clientId":1,"hourBudget":"0","dollarBudget":0,"state":null,"menuType":"","type":"project","modified":"2026-10-27 16:19:21","clientName":"quzuo","start":null,"end":null,"status":null}],"id":32}
]
批量请求体仍是一次 HTTP 请求,所以只占一个限流配额——这是把大量只读查询打包时最划算的做法。
8.2 GET
GET 把参数放在查询串里,params 必须是 base64(JSON):
PARAMS=$(printf '{"id": 2}' | base64 | tr -d '\n')
curl -s -G http://192.168.1.71:8141/api/jsonrpc \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode 'method=leantime.rpc.Projects.getProject' \
--data-urlencode "params=$PARAMS" \
--data-urlencode 'jsonrpc=2.0' \
--data-urlencode 'id=42'
实测回显:
{"jsonrpc":"2.0","result":{"id":2,"name":"API 演示项目","clientId":1,"details":"由 JSON-RPC 创建","psettings":"restricted","clientName":"quzuo","isFavorite":0},"id":"42"}
注意返回的 id 变成了字符串 "42"——GET 模式下所有查询串参数都是字符串,客户端做 id 比对时要宽松处理。GET 适合浏览器直接打开的只读查询,写操作一律用 POST。
九、错误码与排查表
Leantime 的 JSON-RPC 错误全部以 HTTP 200 返回,错误信息在 error 对象里;只有认证与限流走 HTTP 401/429:
| 现象 | code | data 示例 | 处置 |
|---|---|---|---|
| 协议版本不对 | -32600 | Leantime only supports JSON-RPC version 2.0 | 补 "jsonrpc":"2.0" |
| 方法不存在 | -32601 | Method doesn't exist: notAMethod | 核对方法名大小写与拼写 |
| 方法未开放 | -32601 | Method is not available via API: xxx | 找带 @api 的等价方法 |
| 缺必填参数 | -32602 | Required Parameter Missing: id | 按方法签名补参数 |
| 参数类型无法转换 | -32602 | Could not cast parameter: xxx | 传字符串/数字要匹配声明类型 |
| 业务异常 | -32001 / 自定义 | 消息来自异常本身 | 读 message,多为权限或资源不存在 |
| 插件未启用 | -32004 | Plugin 'X' is required but not enabled. | 到后台启用插件 |
| 未认证 | HTTP 401 | {"error":"Unauthorized"} | 补 x-api-key 或 Bearer |
| 限流 | HTTP 429 | Retry-After: n | 按头退避,勿盲目重试 |
| 无响应体(通知) | — | — | 未带 id 的请求按规范不返回响应体 |
实测四条错误回显:
{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request","data":"Leantime only supports JSON-RPC version 2.0"},"id":21}
{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found","data":"Method doesn't exist: notAMethod"},"id":22}
{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params","data":"Required Parameter Missing: id"},"id":24}
排障顺序:先看 HTTP 状态(401/429 属于传输层),再看 error.code(协议层),最后读 error.data(业务层,最具体)。data 里出现 Required Parameter Missing 就直接补参数,不要怀疑权限。
十、日常运维命令
10.1 服务与日志
systemctl status leantime --no-pager
journalctl -u leantime -n 20 --no-pager
应用日志按 LEAN_LOG_CHANNELS 决定去向;实测实例设为 stderr,因此 journalctl 里能直接看到访问日志与限流记录:
127.0.0.1 - 27/Oct/2026:17:01:24 +0000 "POST /index.php" 200
127.0.0.1 - 27/Oct/2026:17:02:23 +0000 "GET /index.php" 429
10.2 应用 CLI:php bin/leantime
CLI 是 Laravel 11.45.1 的命令行外壳,运维常用的四组:
cd /var/www/leantime
# 列全部命令
php bin/leantime list
# 建用户(邮箱 + 密码必填)
php bin/leantime user:add --email=dev2@example.com --password='Dev@q1w2e3r4'
# 改数据库设置(站点名、可信 URL 等)
php bin/leantime setting:save --key=system.trustedAppUrl --value=https://pm.example.com
# 签发/清理认证凭据
php bin/leantime auth:create-bearer-token --email=admin@example.com --name=ci-bot --quiet-output
php bin/leantime auth:clear-resets
实测 setting:save 回显:
[OK] Saved Successfully
这些命令都在应用根目录执行;用 sudo -u www-data 运行可避免生成的缓存文件属主变成 root(属主错乱会导致网页 500)。
10.3 数据库备份与恢复
mysqldump -uleantime -pq1w2e3r4 --single-transaction --quick leantime \
> /opt/backup/leantime-$(date +%F-%H%M).sql
ls -lh /opt/backup/ | tail -2
gzip -c /opt/backup/leantime-2026-10-28-0105.sql | wc -c
实测:初始数据量下备份文件 64 KB,gzip 后 11 269 字节。
-rw-r--r-- 1 root root 64K Oct 28 01:05 leantime-2026-10-28-0105.sql
11269
恢复:
mysql -uleantime -pq1w2e3r4 leantime < /opt/backup/leantime-2026-10-28-0105.sql
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.1.71:8141/auth/login
恢复后要再探一次登录页(期望 200)。--single-transaction 保证 InnoDB 表一致性快照,不要漏掉它;漏了在写入高峰期备份会得到跨表不一致的数据。备份文件里含用户密码哈希与 zp_settings,按敏感数据处理。
10.4 健康检查与例行巡检
# 1. 版本与插件状态(需要 token)
curl -s -X POST http://192.168.1.71:8141/api/jsonrpc \
-H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \
-d '{"jsonrpc":"2.0","method":"leantime.rpc.Api.Config.getSystemInfo","params":{},"id":1}'
# 2. 登录页可达
curl -s -o /dev/null -w '%{http_code} %{time_total}s\n' http://192.168.1.71:8141/auth/login
# 3. 可写目录
ls -ld /var/www/leantime/userfiles /var/www/leantime/storage/logs
三项分别覆盖「应用逻辑」「Web 链路」「磁盘权限」,是每日巡检的最小集合。若第 1 项返回 429 而第 2 项 200,问题在限流阈值而不是服务宕机。
十一、参考链接
- 官方 JSON-RPC 说明:
https://docs.leantime.io(API 章节) - 方法白名单来源:源码
app/Domain/*/Services/*.php中带@api注释的方法 - 同专栏:《Leantime 介绍与选型指南》
- 同专栏:《Ubuntu 22.04 安装 Leantime 3.12.0 指南》
- 同专栏:《Leantime 3.12.0 配置参数详解》