FOSSBilling 0.8.8 API 使用详解
FOSSBilling 0.8.8 REST API 使用详解:guest/client/admin 三层入口与 35 个模块 API 方法数实测盘点、Basic Token 与会话+CSRF 双认证实测、guest/admin/client 域逐命令调用回显、分页与响应信封格式、九类错误码实测清单、限流器 429 触发实录与 api_login 策略挂空观察、curl 全流程示例。
FOSSBilling 0.8.8 API 使用详解
目标:把 FOSSBilling 0.8.8 的 REST API 讲到可以直接抄——三层入口怎么选、怎么认证、每个域怎么调、响应与错误长什么样、限流怎么触发,全部基于一台 Ubuntu 22.04 实测服务器的真实命令与逐行回显(实测日期 2026-10-23)。安装与配置前置见《Ubuntu 22.04 安装 FOSSBilling 0.8.8 指南》与《FOSSBilling 0.8.8 配置参数详解》。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(主机名 billing-server) |
| FOSSBilling | 0.8.8(官方发行包,站点 http://192.168.1.62:8148/) |
| PHP / 数据库 | 8.3.36 / 11.4.13-MariaDB |
| 管理员账号 | admin / Q1w2e3r4(管理后台),Admin API Token 见 3.2 |
| 测试客户 | apitest@quzuo.net / Q1w2e3r4(API Key 见 3.3) |
| 实测工具 | curl 7.81.0(服务器本机 127.0.0.1 调用) |
本篇所有请求均在服务器本机以 curl 发起并记录真实回显;数据库密码与安装篇一致(root / q1w2e3r4)。
二、前置条件
- 已完成 0.8.8 安装并可登录管理后台(安装实录见《Ubuntu 22.04 安装 FOSSBilling 0.8.8 指南》)。
- 了解 API 行为相关的两个配置段(
api与rate_limiter)的含义,详见《FOSSBilling 0.8.8 配置参数详解》的 5.12 与 5.13 节。 - 会用 curl 发 GET/POST 请求;如需在服务器上直接验证,也可用
php /var/www/html/console.php(CLI 工具与 API 相互独立,命令清单见配置篇 5.6 节)。
三、认证凭据准备
3.1 三层入口一览
FOSSBilling 的 REST API 统一挂在 /api/ 下,按「角色/模块/方法」三级路由:
| 入口 | 鉴权要求 | 用途 |
|---|---|---|
| /api/guest/<模块>/<方法> | 无需认证 | 公开数据:商品、货币、注册、登录 |
| /api/client/<模块>/<方法> | 客户身份(Token 或会话) | 客户自助:订单、发票、资料 |
| /api/admin/<模块>/<方法> | 管理员身份(Token 或会话) | 系统管理:客户、发票、员工、统计 |
三层各自独立的方法清单在发行包 modules/<模块>/Api/{Guest,Client,Admin}.php 中,方法名即路由末段。实测对 35 个模块的 API 方法数盘点(统计 public function 定义数):
Activity: Admin=3 Antispam: Guest=1 Admin=4
Cart: Guest=8 Client=1 Admin=3 Client: Guest=7 Client=4 Admin=21
Cookieconsent: Guest=1 Cron: Guest=1 Admin=4
Currency: Guest=3 Admin=10 Custompages: Admin=6
Email: Client=4 Admin=25 Extension: Guest=3 Admin=14
Formbuilder: Guest=1 Admin=12 Hook: Admin=3
Index: Client=1 Invoice: Guest=5 Client=6 Admin=57
Massmailer: Admin=11 News: Guest=2 Admin=6
Notification: Admin=5 Order: Client=6 Admin=26
Page: Admin=1 Product: Guest=5 Admin=26
Profile: Client=7 Admin=7 Redirect: Admin=5
Security: Admin=8 Seo: Admin=2
Serviceapikey: Guest=1 Client=1 Admin=2
Servicecustom: Client=1 Admin=2
Servicedomain: Guest=4 Client=8 Admin=24
Servicedownloadable: Client=1 Admin=4 Servicehosting: Guest=1 Client=6 Admin=23
Servicelicense: Guest=1 Client=2 Admin=4
Staff: Guest=3 Admin=20 Stats: Admin=14
Support: Guest=14 Client=6 Admin=43 System: Guest=13 Admin=27
Theme: Admin=7 Widgets: Admin=2
方法命名规则(官方 API 文档同款约定):小写加下划线(如 get_list、change_password);核心路由 GET 与 POST 均接受,带 JSON 体的请求用 POST;响应恒为 JSON。
3.2 管理员 API Token
Admin API 的 Token 是每个管理员的个人凭据,在管理后台「个人资料」页生成/查看(Admin 模块)。本机实测管理员 Token:
2sR1UbVv4O47TlAUdv2csJKxelGmnJhK
⚠️ API Token 等同账号密码,泄露即等于交出对应身份的全部 API 能力,入库/入代码仓库前务必脱敏。
3.3 客户 API Key
客户的 API Key 在客户区个人资料页查看与重置(Profile 模块提供 api_key_get / api_key_reset 两个接口,同样可在客户区界面操作)。本机为便于演示先由管理员创建测试客户,并为其写入 API Key:
curl -s -u "admin:2sR1UbVv4O47TlAUdv2csJKxelGmnJhK" -X POST \
-H "Content-Type: application/json" \
-d '{"email":"apitest@quzuo.net","password":"Q1w2e3r4","first_name":"API","last_name":"Tester","status":"active"}' \
http://127.0.0.1:8148/api/admin/client/create
实测回显:
{"result":"2","error":null}
返回的 "2" 即新客户 ID。随后为其写入 API Key(正常途径是客户自己在客户区生成,此处为演示直写数据库):
mariadb -uroot -p fossbilling -e \
"UPDATE client SET api_token='f6Qz1fO0TQ4YxHqRS8WkqXcJKDhwN0Yv' WHERE id=2;"
四、认证方式与实测
0.8.8 共两种有效认证,按「调用方形态」选择:
| 方式 | 适用场景 | 机制 |
|---|---|---|
| Basic + Token | 外部系统集成(推荐) | Authorization: Basic base64(角色:API_Token) |
| 会话 Cookie + CSRF | 客户区/管理区网页内调用 | 登录后的会话 Cookie + CSRFToken 参数 |
4.1 Basic Token 认证(外部集成首选)
源码判据(modules/Api/Controller/Client.php):Basic 认证的用户名必须是路由角色(admin 域填 admin,client 域填 client),密码填 API Token;系统内置的「System Cron Job」管理员不参与 API 认证。实测两种正确写法:
# admin 域:用户名固定 admin,密码为管理员 Token
curl -s -u "admin:2sR1UbVv4O47TlAUdv2csJKxelGmnJhK" \
-X POST http://127.0.0.1:8148/api/admin/client/get_list
实测回显:
{"result":{"pages":1,"page":1,"per_page":100,"total":2,"list":[...]}, "error":null}
# client 域:用户名固定 client,密码为客户 API Key
curl -s -u "client:f6Qz1fO0TQ4YxHqRS8WkqXcJKDhwN0Yv" \
http://127.0.0.1:8148/api/client/profile/get
实测回显:
{"result":{"id":2,"email":"apitest@quzuo.net","email_approved":null,"type":null,"first_name":"API","last_name":"Tester","gender":null,"birthday":null,"phone_cc":null,"phone":null,"company":null,"company_vat":null,"company_number":null,"address_1":null,"address_2":null,"city":null,"state":null,"postcode":null,"country":null,"currency":null,"lang":null,"timezone":null,"billing_email":null,"balance":0},"error":null}
💡 关键实测结论:Token 认证不要求 CSRF——CSRF 防护只作用于会话认证的调用(源码分支
_tryTokenLogin路径无 CSRF 校验,官方文档亦如此描述)。外部集成一律走 Token,可完全避开 CSRF 问题。
4.2 会话认证与 CSRF(网页内调用)
浏览器里已登录的客户/管理员调用 API 时走会话 Cookie。此时必须携带 CSRF Token,源码接受四种位置之一:JSON 体 CSRFToken 字段、表单/查询参数 CSRFToken、X-CSRF-TOKEN 请求头,且须与会话内 Token 一致。实测不带 CSRF Token 的会话调用直接被拒:
# 用客户登录获得会话
curl -s -c /tmp/fb_cookie.txt -X POST -H "Content-Type: application/json" \
-d '{"email":"apitest@quzuo.net","password":"Q1w2e3r4"}' \
http://127.0.0.1:8148/api/guest/client/login
实测回显:
{"result":{"id":2,"email":"apitest@quzuo.net","name":"API Tester","role":"client"},"error":null}
# 仅凭会话 Cookie 调 client 域(无 CSRF Token)
curl -s -b /tmp/fb_cookie.txt http://127.0.0.1:8148/api/client/profile/get
实测回显:
{"result":null,"error":{"message":"CSRF token invalid","code":403}}
这正是 config.php 中 api.CSRFPrevention=true 的防护效果。网页端(客户区/管理区的 JS)会自动从 Cookie 读取 Token 附加提交;纯 API 集成请改用 4.1 的 Token 认证。另注意实测细节:登录接口的响应不会下发 CSRF Cookie,CSRF Token 由页面模板内嵌/由会话生成——所以拿 curl 模拟「先登录再调 API」的会话路径,本质上缺少网页上下文,不适用于集成场景。
4.3 guest 域无需认证
curl -s -X POST http://127.0.0.1:8148/api/guest/system/company
实测回显:
{"result":{"company":{"name":"Company Name","email":"support@yourcompany.com","tel":"+123 456 12345","signature":"FOSSBilling.org - Client Management, Invoicing and Support Software","logo_url":"http://192.168.1.62:8148/public/branding/logo.svg","address_1":"Demo address line 1","address_2":"Demo address line 2","address_3":"Demo address line 3","privacy_policy":"This is a sample Privacy Policy. Please replace this with your own...","tos":"This is a sample Terms of Service. Please replace this with your own...","note":"This is a placeholder for your About Us page. It will be available once you customize it in the admin panel."},"error":null}
GET 同样可用:
curl -s "http://127.0.0.1:8148/api/guest/system/periods"
实测回显(节选):
{"result":["Free","One Time","Recurring","Weekly","Monthly","Quarterly","Semi-Annually","Yearly","Every 2 years","Every 3 years"],"error":null}
五、分页与响应格式
5.1 分页参数与回显
列表类接口统一支持 per_page 与 page(GET 查询参数或 JSON 体均可),实测:
curl -s -u "admin:2sR1UbVv4O47TlAUdv2csJKxelGmnJhK" \
"http://127.0.0.1:8148/api/admin/client/get_list?per_page=5&page=1"
实测回显(节选):
{"result":{"pages":1,"page":1,"per_page":5,"total":2,"list":[...]},"error":null}
不传分页参数时默认 per_page=100。字段含义:total 全量条数、pages 总页数、page 当前页、list 当前页数据。
5.2 响应信封
所有接口返回统一信封 {"result": ..., "error": ...}:
- 成功:
result为数据(对象/数组/字符串),error为null; - 失败:
result为null,error为{message, code}对象; - 空字段以
null显式返回(官方文档明确:不省略字段);日期为 ISO 8601。
单对象查询示例(admin/client/get 按 ID 取客户):
curl -s -u "admin:2sR1UbVv4O47TlAUdv2csJKxelGmnJhK" -X POST \
-H "Content-Type: application/json" -d '{"id":2}' \
http://127.0.0.1:8148/api/admin/client/get
实测回显(节选):
{"result":{"id":2,"email":"apitest@quzuo.net","email_approved":null,"type":null,"first_name":"API","last_name":"Tester",...},"error":null}
六、实战:以 JSON 体重建客户资料
POST + JSON 体是写操作的标准姿势(Content-Type: application/json),3.3 的建户示例即此模式。重复提交同一邮箱时的真实报错回显:
curl -s -u "admin:2sR1UbVv4O47TlAUdv2csJKxelGmnJhK" -X POST \
-H "Content-Type: application/json" \
-d '{"email":"apitest@quzuo.net","password":"Q1w2e3r4","first_name":"API","last_name":"Tester","status":"active"}' \
http://127.0.0.1:8148/api/admin/client/create
实测回显:
{"result":null,"error":{"message":"This email address is already registered. Please try again or contact support.","code":9999}}
管理域批量取数示例(员工列表):
curl -s -u "admin:2sR1UbVv4O47TlAUdv2csJKxelGmnJhK" \
-X POST http://127.0.0.1:8148/api/admin/staff/get_list
实测回显:
{"result":{"1":{"id":"1","role":"admin","admin_area_ip":null,"email":"admin@example.com","name":"Admin","status":"Active","signature":"","created_at":"2026-10-23T05:56:09+0000"},"0":{"id":1,"role":"admin","email":"admin@example.com","name":"Admin","status":"Active"}},"error":null}
七、错误码与报错实录
以下错误码全部在本机实测触发,可直接当排障对照表用:
| code | message(实测) | 触发方式 |
|---|---|---|
| 201 | Authentication Failed | 未认证会话调用 client/admin 域(如裸 curl 调 client 域) |
| 205 | Authentication Failed | Basic 认证 Token 错误 |
| 401 | Please check your login details. | guest/client/login 账号密码错误 |
| 403 | CSRF token invalid | 会话调用未带/带错 CSRF Token |
| 429 | Rate limit exceeded. Please try again later. | 触发限流策略(见第八节) |
| 715 | FOSSBilling module <模块> is not installed/activated | 调用未安装模块(如 /api/admin/notamodule/get_list) |
| 740 | <域> API call <方法> does not exist in module <模块> | 模块存在但方法不存在(如 guest/system/version) |
| 9999 | 业务校验消息(逐接口不同) | 参数缺失(Client ID or email is required)、邮箱重复等 |
两个值得记录的实测细节:
/api/guest/system/version在 0.8.8 不存在(返回 740)。版本信息不走 API,用 CLI:php /var/www/html/console.php system:version,实测输出FOSSBilling 0.8.8。- HTTP 状态码与业务 code 并行:登录失败这类业务错误 HTTP 层仍返回 200(信封里
error.code=401),而 CSRF/限流这类框架层错误分别返回 403/429——判断成败应以信封error字段为准。
八、限流实测
API 限流由 config.php 的 rate_limiter 段控制(策略全表见《FOSSBilling 0.8.8 配置参数详解》的 5.13 节)。实测 guest 域匿名调用策略 api_guest(token_bucket,100 次/60 秒):
# 连发 130 次匿名请求,记录第 101 次起的响应
for i in $(seq 1 130); do
r=$(curl -s -o /tmp/rlb.txt -w "%{http_code}" http://127.0.0.1:8148/api/guest/system/company)
if [ "$r" != "200" ]; then echo "attempt $i -> HTTP $r"; cat /tmp/rlb.txt; break; fi
done
实测回显:
attempt 101 -> HTTP 429
{"result":null,"error":{"message":"Rate limit exceeded. Please try again later.","code":429}}
429 响应头实测带恢复提示:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
清理限流状态(缓存存储,按 IP 计):
sudo -u www-data php /var/www/html/console.php cache:clear
💡 实测观察(0.8.8):源码为登录暴破防护保留了
api_login策略(10 次/小时),但它只挂在名为client_login/staff_login的方法上——实测/api/guest/client/client_login、/api/guest/staff/client_login均返回 740(方法不存在),实际登录方法名是login。即 0.8.8 实际登录路径只受api_guest桶限制,暴破防护未真正生效;对外网开放注册/登录的实例建议自行加一层前置限流(如 Nginx limit_req),或持续关注版本更新。
九、常见问题(FAQ)
Q1:curl 调用报 CSRF token invalid(403)?
会话 Cookie 认证必须带 CSRF Token,而 curl 拿不到会话内 Token。外部集成改用 Basic Token 认证(4.1),网页内调用则由前端 JS 自动携带。若确需临时关闭该防护,改 config.php 的 api.CSRFPrevention => false——官方注释明确警告不要在生产关闭。
Q2:管理后台登录后,浏览器里能调 admin API,脚本里却报 Authentication Failed?
浏览器走会话,脚本没带会话。脚本用 curl -u "admin:<API_Token>"(用户名固定 admin)。另外注意:Basic 认证的密码是 API Token 而非后台登录密码。
Q3:怎么查某模块有哪些可用方法?
三层方法与路由一一对应,直接看发行包源码最准:modules/<模块>/Api/Guest.php|Client.php|Admin.php 里的 public function 即方法名。3.1 节的清单给出了 35 个模块各层的方法数,可据此定位模块。
Q4:接口偶发 Invalid request. Make sure request origin is http://...?
url 配置与请求来源不一致触发来源校验拦截(config.php 的 url 键,见配置篇 5.4)。改域名/换端口后同步修改 url 并保持尾斜杠。
Q5:大量集成调用被 429?
按第八节处理:为固定来源 IP 配 rate_limiter.whitelist_ips,或用 policies 覆盖对应策略的上限(只覆盖需要调的那一条)。不要整体关闭限流。
十、参考链接
- 官方 API Reference(三层入口、Basic 认证、CSRF 位置等约定与本文实测一致):
https://docs.fossbilling.org/extensions-and-development/api/ - 本专栏安装实战:《Ubuntu 22.04 安装 FOSSBilling 0.8.8 指南》
- 本专栏配置手册:《FOSSBilling 0.8.8 配置参数详解》(api 与 rate_limiter 配置段、限流策略全表)
- 本专栏选型认知:《FOSSBilling 0.8.8 介绍与选型指南》
- API 方法源码:发行包内
modules/<模块>/Api/{Guest,Client,Admin}.php与modules/Api/Controller/Client.php(认证/限流/CSRF 判据)