P.H.M. API
Phira / Phigros 谱面难度参考接口。查询已缓存的定数,或分析一张谱并写入共享缓存。 免费;匿名可用,API Key 获得更高额度。
ref_const 是社区共识标度,
ref_official 是官谱标度。两者不可混比,细节见首页说明。
快速开始
API 是普通的 HTTPS + JSON,不需要 SDK。先拿到一个 API Key(开放平台),或者直接用匿名额度试:
带 Key 的请求(推荐 x-phm-key):
JavaScript:
Python:
在线试一下
不用装任何东西,在这里直接打一次真实的请求。Key 可以留空 —— 留空就走匿名额度。
点「发送请求」看结果。
x-phm-key —— 这也是你该用的那个头。
认证
两种身份:
- 匿名:不带任何鉴权头,按真实对端 IP 限流(100 次/小时);
- API Key:
x-phm-key: sk-<32 位十六进制>(推荐), 也可用Authorization: Bearer sk-…(兼容,但可能失效,见下)。
x-phm-key:本站部署在一个会改写鉴权头的网关后面,
实测两种常见写法都不可靠 ——①
Authorization:网关会写入它自己的值,把你的盖掉;②
x-api-key:网关把它当成自己的鉴权头消费掉,服务端收不到;③
x-phm-key:私有名字,网关不碰,稳定生效。失效时的表现很隐蔽:不报错,只是静默降级成匿名(1000 次/小时 → 100 次/小时)。
自检方法:把 Key 换成一把不存在的
sk-(格式仍要对),
正常应返回 401 invalid_api_key;如果仍返回 200,
说明 Key 没送达,你正在以匿名身份被限流。更直接:打开 /api/v1/meta?diag=1, 看
diag 里各头的长度 —— 0 表示这个头没穿透到服务端。
Key 的明文只会在创建时返回一次;服务端只存 sha256 哈希与掩码。每个账号最多 100 个有效 Key,可随时吊销。
限流
| 身份 | 额度 | 说明 |
|---|---|---|
| 匿名 | 100 次/小时 | 真实对端 IP + 全局桶 |
| API Key | 1000 次/小时 | 分析另有 200 次/天 |
超限返回 429,并带 retry-after;服务端限流器不可用时返回 503。
查询定数
GET /charts/{chart_id}
读共享缓存。未分析过的谱返回 analyzed:false(不是 404)。
列出谱面
GET /charts
分页浏览共享缓存。这是唯一能"不知道 id 也能用"的接口 ——
/charts/{id} 需要你先知道是哪张谱,而这里可以搜索、排序、翻页。
| 参数 | 默认 | 说明 |
|---|---|---|
page | 1 | 页码,从 1 开始 |
pageSize | 50 | 每页条数,上限 200 |
sort | chart_id | 排序字段,白名单:chart_id / name / level / difficulty / ref_const / ref_official / ps_score / nps / notes。传别的值返回 400 |
order | asc | asc 或 desc |
q | — | 按谱面名做子串匹配(最多 60 字符) |
level | — | 难度前缀过滤,如 IN / AT / SP |
only | — | official = 只要算得出官谱标度的;stale = 引擎版本与基准不一致的 |
build | — | 判过期用的基准引擎版本,仅在 only=stale 时有意义 |
响应(total 是真实总数,不是本页条数,可以直接算页数):
搜索:
全库统计
GET /stats
共收录多少谱、覆盖多少、活跃用户多少。与首页展示的数字同源。
谱师作品
GET /charters/{uid}
某个谱师(Phira 用户 id)上传过的谱面,并自动贴上本站已算好的定数。
| 参数 | 默认 | 说明 |
|---|---|---|
uid(路径) | 必填 | Phira 用户 id,纯数字 |
maxPages | 3 | 向上游读几页(每页 30 张),上限 5 —— 硬上限,避免这个接口变成爬虫入口 |
①
analyzed:false 表示本站还没算过这张谱 —— 此时
ref_const 等字段不存在。缺字段和"算出来是 0"是两件事,别用 0 兜底。② 上游挂了返回 502,不会返回空数组。空数组会被读成"这位谱师没有作品", 那是最坏的错误答案 —— 宁可报错让你重试。
玩家资料
GET /players/{uid}
公开资料 + 统计。不含成绩明细:把几百条记录塞进一个响应,既慢又容易被批量抓。
uid 不存在返回 404 player_not_found。
stats 是可选增强:拿不到时为 null,请求本身仍然成功。
分析谱面
POST /analyses
服务端从 Phira 下载谱面、复算并写入共享缓存。v1 只接受 chart_id;分析结果对之后所有查询直接可用。
已缓存时直接返回(cached:true);未缓存时会下载 ≤60MB 谱面并运行引擎,可能需要几秒。并发上限 2,忙时返回 503 analysis_busy。
用量
GET /usage
用 API Key 调用时返回该 Key 所属账号的用量;开放平台用账号 token 调用也可以。
Key 管理
在 API 开放平台 登录后创建、改名、设置权限/到期、轮换、吊销。删除(吊销)后 Key 会立即从列表消失,历史用量仍保留。
charts:read(查询)、analyses:write(分析)、usage:read(用量)。
缺 scope 返回 403 insufficient_scope;过期返回 401 expired_api_key。
创建时可设 30/90/365 天或永不过期;轮换会新建同权限 Key 并立即吊销旧 Key。
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /keys | 列出当前账号的有效 Key(吊销后不再返回;不含明文) |
POST | /keys | 创建,返回一次明文;body 可带 scopes[] / expires_in_days |
PATCH | /keys/{id} | 改名 / 改 scopes / 改到期 |
POST | /keys/{id}/rotate | 轮换:新 Key + 吊销旧 Key |
DELETE | /keys/{id} | 吊销 |
这些接口要求网页账号 token(x-hm-token),不是 sk- key。
错误码
错误统一为:
| HTTP | code | 含义 |
|---|---|---|
| 400 | invalid_chart_id | chart_id 不是正整数 |
| 400 | invalid_uid | 谱师 / 玩家的 uid 不是正整数 |
| 400 | invalid_sort_field | sort 不在白名单里(响应头 x-allowed-sort 给出全部可选值) |
| 404 | player_not_found | 该 Phira 用户不存在 |
| 404 | not_found | 端点不存在 |
| 401 | invalid_api_key | Key 不存在、格式错或已吊销 |
| 401 | account_token_required | Key 管理需要登录 |
| 401 | expired_api_key | Key 已过期 |
| 403 | insufficient_scope | Key 缺少该接口所需 scope |
| 409 | key_limit_reached | 账号已有 100 个有效 Key |
| 429 | rate_limit_exceeded | 超出小时额度 |
| 502 | analysis_failed / cache_unavailable | 数据库暂时不可用 |
| 502 | upstream_unavailable | Phira 上游暂时不可用(谱师 / 玩家接口)。不是「没有数据」,请重试而不是当作空结果 |
| 502 | stats_unavailable | 统计服务暂时不可用 |
| 503 | analysis_busy / rate_limit_unavailable | 分析并发已满 / 限流器故障 |
更新日志
- 2026-10-18 · v1.2:新增
/charts列表(分页 / 搜索 / 排序 / 过滤)、/stats全库统计、/charters/{uid}谱师作品、/players/{uid}玩家资料;端点从 9 个扩到 13 个。鉴权头改为推荐x-phm-key(原因见「认证」一节)。 - 2026-10-17 · v1.1:Key scopes / 过期 / 轮换;按 Key 用量;
/meta构建信息;OpenAPI 单一契约/api/v1/openapi.json。 - 2026-10-17 · v1:首个公开版本。查询 / 分析 / 用量 / Key 管理;匿名 100 次/小时,Key 1000 次/小时、分析 200 次/天。