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 全流程示例。

FOSSBillingREST APIPHP自托管2026/10/23

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)
FOSSBilling0.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)。

二、前置条件

三、认证凭据准备

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}

七、错误码与报错实录

以下错误码全部在本机实测触发,可直接当排障对照表用:

codemessage(实测)触发方式
201Authentication Failed未认证会话调用 client/admin 域(如裸 curl 调 client 域)
205Authentication FailedBasic 认证 Token 错误
401Please check your login details.guest/client/login 账号密码错误
403CSRF token invalid会话调用未带/带错 CSRF Token
429Rate limit exceeded. Please try again later.触发限流策略(见第八节)
715FOSSBilling 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 覆盖对应策略的上限(只覆盖需要调的那一条)。不要整体关闭限流。

十、参考链接

  1. 官方 API Reference(三层入口、Basic 认证、CSRF 位置等约定与本文实测一致):https://docs.fossbilling.org/extensions-and-development/api/
  2. 本专栏安装实战:《Ubuntu 22.04 安装 FOSSBilling 0.8.8 指南》
  3. 本专栏配置手册:《FOSSBilling 0.8.8 配置参数详解》(api 与 rate_limiter 配置段、限流策略全表)
  4. 本专栏选型认知:《FOSSBilling 0.8.8 介绍与选型指南》
  5. API 方法源码:发行包内 modules/<模块>/Api/{Guest,Client,Admin}.php 与 modules/Api/Controller/Client.php(认证/限流/CSRF 判据)