solidtime v0.21.0 API 使用详解
solidtime v0.21.0 REST API 逐接口实测:Token 签发、组织/项目/任务/计时条目 CRUD 与启停计时,含 Passport 客户端初始化、color 小写校验、PATCH 批量语义等六个真实踩坑。
solidtime v0.21.0 API 使用详解
目标:在真实部署的 solidtime v0.21.0 实例上,从认证、组织、项目、任务到计时条目,逐接口实测 REST API 的调用方法、请求响应形态与踩坑结论。实例由 Docker Compose 部署(见《solidtime v0.21.0 Docker Compose 部署指南》),全部请求均为 2026-10-24 实测记录。接口全集以官方 OpenAPI 3.1 规范为底本(54 个路径),本篇覆盖核心 CRUD 链路。
一、API 总览
- Base URL:
http://<APP_URL>/api/v1(本篇实例为http://localhost:8137/api/v1,路径中的/v1由规范固定) - 协议:REST + JSON,规范版本 OpenAPI 3.1.0
- 认证:
Authorization: Bearer <token>(个人访问令牌);未认证返回 401:
curl -sS -w ' HTTP=%{http_code}\n' -H 'Accept: application/json' http://localhost:8137/api/v1/users/me
# 实测输出:
{"message":"Unauthenticated."} HTTP=401
- 通用请求头:
Accept: application/json(缺省时部分接口返回 HTML 错误页);写操作加Content-Type: application/json - 列表类响应统一为
{data, links, meta}信封(links/meta 承载分页),单对象响应为{data: {...}} - 限流:认证用户 200 次/分钟、访客 60 次/分钟(
APP_ENV=production时强制,实测精准触发,见配置篇第 10 节)
1.1 v0.21.0 接口地图(实测涉及✓)
| 域 | 路径 | 方法 |
|---|---|---|
| 用户 | /v1/users/me ✓、/v1/users/me/memberships ✓、/v1/users/me/api-tokens、/v1/users/me/time-entries/active ✓ | GET/POST/DELETE |
| 组织 | /v1/organizations ✓、/v1/organizations/{org} ✓ | POST/GET/PUT/DELETE |
| 成员 | /v1/organizations/{org}/members ✓、invitations ✓ | GET/POST/DELETE |
| 项目 | /v1/organizations/{org}/projects ✓ | GET/POST/PUT/DELETE |
| 任务 | /v1/organizations/{org}/tasks ✓ | GET/POST/PUT/DELETE |
| 计时 | /v1/organizations/{org}/time-entries ✓、time-entries/{id} ✓、aggregate、export | GET/POST/PATCH/PUT/DELETE |
| 报表 | /v1/organizations/{org}/reports、charts/* | GET/POST |
二、认证:创建个人 API Token
2.1 前置:Passport 个人访问客户端(一次性,官方文档未提的坑)
全新实例第一次创建 Token 会报错,实测过程:
docker compose exec -T scheduler php artisan tinker --execute='...createToken(...)'
# 实测失败输出:
RuntimeException Personal access client not found for 'users' user provider. Please create one.
原因:PASSPORT 密钥对(部署篇 2.4 节生成)只是签名材料,Passport 的个人访问客户端记录还需一次性创建:
docker compose exec -T scheduler php artisan passport:client --personal --name="solidtime-personal" --provider=users --no-interaction
# 实测输出:
INFO New client created successfully.
2.2 签发 Token(实测可用)
官方路径是网页端「用户设置 → API 令牌」;CLI 实测路径(真实执行):
docker compose exec -T scheduler php artisan tinker --execute='$u=\App\Models\User::where("email","admin@solidtime.local")->first(); $t=$u->createToken("d5-cli-token"); echo $t->accessToken;'
实测返回 1081 字符的 JWT 形态 Token(形如 eyJ0eXAiOiJKV1QiLCJhbGci...,仅创建时完整展示一次,请立即保存)。Token 管理接口:GET/POST /v1/users/me/api-tokens、POST /v1/users/me/api-tokens/{id}/revoke、DELETE /v1/users/me/api-tokens/{id}。
三、用户与组织
3.1 当前用户:GET /v1/users/me
curl -sS -H "Authorization: Bearer $TOK" -H 'Accept: application/json' http://localhost:8137/api/v1/users/me
实测响应(节选):
{"data":{"id":"eee4c078-6503-46cc-819c-82b29d165b08","name":"admin","email":"admin@solidtime.local","timezone":"UTC","week_start":"monday","currency":"EUR"}}
3.2 创建组织:POST /v1/organizations
curl -sS -X POST -H "Authorization: Bearer $TOK" -H 'Accept: application/json' -H 'Content-Type: application/json' \
-d '{"name":"demo"}' http://localhost:8137/api/v1/organizations
实测响应(节选):
{"data":{"id":"8b787d7d-65cd-4450-9197-b6fe00cd5f8d","name":"demo","is_personal":false,"currency":"EUR","currency_symbol":"€","number_format":"point-comma"}}
组织 ID(下文记 $ORG)从响应 data.id 获取。实测发现:CLI 建号后系统会自动创建一个名为「admin's Organization」的组织(is_personal=true),与手工创建的并存,多组织通过 PUT /v1/users/me/current-organization 切换。
3.3 成员身份:GET /v1/users/me/memberships
curl -sS -H "Authorization: Bearer $TOK" -H 'Accept: application/json' http://localhost:8137/api/v1/users/me/memberships
实测响应(节选):
{"data":[
{"id":"9355d38b-b982-4f5e-8392-0e1e0b39d590","organization":{"id":"9d9f7e8e-...","name":"admin's Organization"},"role":"owner"},
{"id":"2d529b17-24ec-466c-b441-8e905514e0aa","organization":{"id":"8b787d7d-...","name":"demo"},"role":"owner"}
]}
membership 的 id 即创建计时条目时要用的 member_id。
3.4 邀请成员:POST /v1/organizations/{org}/invitations
实测必须带 role(缺省 422:The role field is required.),取值 admin/member 等:
curl -sS -X POST -H "Authorization: Bearer $TOK" -H 'Accept: application/json' -H 'Content-Type: application/json' \
-d '{"email":"newmember@example.com","role":"admin"}' http://localhost:8137/api/v1/organizations/$ORG/invitations
重复邀请实测返回 400(幂等保护):
{"error":true,"key":"invitation_for_the_email_already_exists","message":"The email has already been invited to the organization..."}
邀请触发队列发信(MAIL_MAILER=log 下邮件全文落在 worker 日志,实测见配置篇 7.1)。
四、项目与任务
4.1 创建项目:POST /v1/organizations/{org}/projects
必填:name、color、is_billable、client_id(可为 null)。
实测踩坑(color 格式):先以 #3B82F6(大写)请求返回 422:
{"message":"The color field must be a valid color.","errors":{"color":["The color field must be a valid color."]}} HTTP=422
查实例内源码(app/Service/ColorService.php)确认校验正则为 ^#[0-9a-f]{6}$——# 后必须 6 位小写十六进制。改 #3b82f6 重试成功:
curl -sS -X POST -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"name":"Website Redesign","color":"#3b82f6","is_billable":true,"client_id":null}' \
http://localhost:8137/api/v1/organizations/$ORG/projects
实测响应(节选):{"data":{"id":"360eb57c-...","name":"Website Redesign","color":"#3b82f6","is_billable":true}}(下文记 $PID)。
列表形态(GET .../projects):{"data":[...],"links":{...},"meta":{...}}。
4.2 创建任务:POST /v1/organizations/{org}/tasks
必填:name、project_id。
curl -sS -X POST -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"name":"API 实测任务","project_id":"'$PID'"}' http://localhost:8137/api/v1/organizations/$ORG/tasks
实测响应(节选):{"data":{"id":"72cf4be1-...","name":"API 实测任务","project_id":"360eb57c-..."}}(下文记 $TID)。
4.3 删除保护:DELETE /v1/organizations/{org}/tasks/{task}
任务已被计时条目引用时实测删除被拒(引用完整性):
{"error":true,"key":"entity_still_in_use","message":"The task is still used by a time entry and can not be deleted."} HTTP=400
五、计时条目(核心域)
5.1 创建计时:POST /v1/organizations/{org}/time-entries
必填:member_id、start、billable。end 传 null 即运行中条目:
curl -sS -X POST -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"member_id":"2d529b17-...","project_id":"'$PID'","task_id":"'$TID'","start":"2026-10-24T12:35:49Z","end":null,"billable":true,"description":"D5 API 实测条目"}' \
http://localhost:8137/api/v1/organizations/$ORG/time-entries
实测响应(节选):{"data":{"id":"0fb069b2-...","start":"2026-10-24T12:35:49Z","end":null,"billable":true}}(记 $TE)。可选字段:tags(数组)、type(time/break)。
5.2 查询运行中条目:GET /v1/users/me/time-entries/active
curl -sS -H "Authorization: Bearer $TOK" -H 'Accept: application/json' http://localhost:8137/api/v1/users/me/time-entries/active
# 实测响应(节选):
{"data":{"id":"0fb069b2-442c-463d-96c1-2cb574cb7b7f",...}}
5.3 停止计时:PUT /v1/organizations/{org}/time-entries/{id}
curl -sS -X PUT -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"start":"2026-10-24T12:35:49Z","end":"2026-10-24T12:36:40Z"}' \
http://localhost:8137/api/v1/organizations/$ORG/time-entries/$TE
# 实测响应(节选):
{"data":{...,"end":"2026-10-24T12:36:40Z","duration":51}}
duration 由服务端按 start/end 计算(秒)。
实测踩坑(PATCH 是批量语义):集合上的 PATCH /time-entries 并非单条更新,实测必须传 ids + changes;且查源码(TimeEntryUpdateMultipleRequest)确认 changes 仅允许 member_id/project_id/task_id/billable/type/description/tags——不含 start/end,强传实测返回 500 {"message":"Server Error"}。改 start/end 必须走 5.3 的单条 PUT。
5.4 列表与统计
curl -sS -H "Authorization: Bearer $TOK" -H 'Accept: application/json' http://localhost:8137/api/v1/organizations/$ORG/time-entries
实测响应字段(首条):id, start, end, duration, description, task_id, project_id, organization_id, user_id, tags, billable, type。同域还有 aggregate(聚合统计)、export(CSV 导出)、charts/*(仪表盘图表)等只读接口,参数结构见 OpenAPI 规范。
六、实测踩坑速查
| # | 坑 | 现象 | 处置 |
|---|---|---|---|
| 1 | 全新实例无 Passport 个人客户端 | createToken 报 Personal access client not found | 先跑一次 passport:client --personal(2.1 节) |
| 2 | color 大写十六进制 | 422 must be a valid color | # + 6 位小写 hex(源码正则核实) |
| 3 | PATCH 集合当单条更新用 | 422 要求 ids/changes;强传 start/end 500 | PATCH=批量改属性;改时间用单条 PUT |
| 4 | 删除被引用的任务 | 400 entity_still_in_use | 先删/改引用它的计时条目 |
| 5 | 邀请缺 role | 422 The role field is required. | 显式传 admin/member |
| 6 | 缺 Accept: application/json | 错误响应可能为 HTML 页 | 统一携带 Accept 头 |
七、参考链接
- 官方 API 文档入口:https://docs.solidtime.io/api
- OpenAPI 3.1 规范(本篇底本):官方 API 文档页内嵌规范文件,共 54 个路径
- 本专栏其他篇目:《solidtime v0.21.0 介绍与选型指南》《solidtime v0.21.0 Docker Compose 部署指南》《solidtime v0.21.0 配置参数详解》