Kill Bill 0.24.22 API 使用详解

curl 直连 Kill Bill 0.24.22 REST API 实测计费全生命周期:租户/目录/账户/支付方式/订阅/发票/收款/Credit/取消全链路带真实回显,认证三件套、分页响应头约定、错误体结构与 415/400/401/404 排障实录。

Kill BillKill Bill订阅计费REST API自托管2026/10/24

Kill Bill 0.24.22 API 使用详解

目标:以 curl 直连 Kill Bill 0.24.22 REST API,完整实测一条计费生命周期链路——创建租户、上传定价目录、建立账户与支付方式、开通订阅、生成发票、收款、账户 Credit 到订阅取消,每个命令带真实回显与错误排障实录;并覆盖认证三件套、分页约定与错误体结构。Kill Bill 无活跃维护的 CLI 工具(官方 kb-cli 已多年未更新),REST API 就是其运维与集成的主接口,故本篇以 API 为主线。

一、环境信息

  • 操作系统:Ubuntu 22.04.4 LTS(内核 6.8.0-138-generic)
  • Kill Bill:0.24.22(API 服务地址 http://<服务器IP>:8146,端口与部署见 《Kill Bill 0.24.22 Docker Compose 部署指南》)
  • KAUI 管理界面:4.0.31(http://<服务器IP>:8147,本文命令均可与 KAUI 界面操作互相印证)
  • 数据库:killbill/mariadb 0.24
  • 演示凭据:API 管理员 admin,口令 q1w2e3r4(由部署时 KB_ADMIN_PASSWORD 注入);租户密钥 bob / lazar(本文实测创建的演示租户)
  • 实测日期:2026-10-23;Swagger 描述文件 http://<服务器IP>:8146/swagger 可获取全部端点定义

二、前置条件

  1. Kill Bill 服务已就绪(Swagger 描述文件返回 200):
    curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8146/swagger
    
    实测回显:
    200
    
  2. 具备 curl(或 Postman 等任意 HTTP 客户端);
  3. 理解 Kill Bill API 的认证模型(见第三节):每个请求需要 HTTP Basic 管理员凭据 + 租户密钥双头,缺一个都是 401。

三、认证方式

Kill Bill API 认证由两层构成(每请求必须同时携带):

层形式说明
管理员凭据HTTP Basic(-u admin:q1w2e3r4)认证「操作者」,由 shiro 配置决定(见配置篇 3.4)
租户密钥X-Killbill-ApiKey + X-Killbill-ApiSecret 头认证「业务租户」,多租户隔离的凭证

审计头(可选但推荐):X-Killbill-CreatedBy: admin 标记操作来源,会写入每条资源的审计日志。

认证失败的实测表现(缺租户密钥或密钥错误均返回 401):

curl -s -o /dev/null -w '%{http_code}\n' -u admin:q1w2e3r4 http://127.0.0.1:8146/1.0/kb/catalog

实测回显:

401

补齐三件套后:

curl -s -o /dev/null -w '%{http_code}\n' -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' http://127.0.0.1:8146/1.0/kb/catalog

实测回显:

200

💡 说明:本文为便于复制,示例统一以 http://127.0.0.1:8146 为基地址、演示租户 bob/lazar、管理员 admin/q1w2e3r4。生产环境请替换为自有地址与强凭据。

四、快速开始:首次部署的初始化三步

全新部署的数据库没有任何租户与目录,先完成初始化(顺序固定):

4.1 创建租户

curl -s -X POST 'http://127.0.0.1:8146/1.0/kb/tenants' \
  -u admin:q1w2e3r4 \
  -H 'Content-Type: application/json' \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  --data '{}'

实测回显(HTTP 201,响应体为空,新租户的 ApiKey/ApiSecret 取自请求头):

http=201

重复执行同一命令的实测回显(排障点:幂等报错,说明已存在):

{"className":"org.killbill.billing.tenant.api.TenantApiException","code":20000,"message":"Tenant already exists for key null","causeClassName":null,"causeMessage":null,"stackTrace":[]}

4.2 上传定价目录

目录是 XML 文件(官方示例 SpyCarAdvanced.xml 包含 Standard/Gold 等产品与 standard-monthly 等计划)。以 text/xml 方式上传(排障实录:用 application/xml 会得到 415 Unsupported Media Type,0.24.22 该端点仅接受 text/xml):

curl -s -X POST 'http://127.0.0.1:8146/1.0/kb/catalog' \
  -u admin:q1w2e3r4 \
  -H 'Content-Type: text/xml' \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  --data-binary @SpyCarAdvanced.xml

实测回显(HTTP 201,响应体为空):

http=201

4.3 验证目录

curl -s -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' http://127.0.0.1:8146/1.0/kb/catalog

实测回显(输出节选,目录版本已生效,含产品与计划):

[
    {
        "versionDate": "2024-01-02T00:00:00Z",
        "products": [
            {
                "name": "Standard",
                "category": "BASE"
            },
            {
                "name": "Gold",
                "category": "BASE"
            }
        ],
        "plans": [
            {
                "name": "standard-monthly",
                "billingPeriod": "MONTHLY"
            }
        ]
    }
]

💡 说明:GET 同一端点带 Accept: application/xml 头可取回原始 XML;JSON 形态适合脚本比对。上传后版本化生效,订阅请求里的 planName 必须与目录中的计划名精确一致。

五、核心 API 分类详解

5.1 账户管理(/1.0/kb/accounts)

创建账户:

curl -s -X POST 'http://127.0.0.1:8146/1.0/kb/accounts' \
  -u admin:q1w2e3r4 \
  -H 'Content-Type: application/json' \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  --data '{"name":"测试客户A","email":"custa@example.com","currency":"USD"}' \
  -D - -o /dev/null

实测回显(HTTP 201,Location 头返回新账户地址):

HTTP/1.1 201 Created
Location: http://127.0.0.1:8146/1.0/kb/accounts/8fd8790e-44eb-41e1-8202-bcef9c3c8c20

查询账户(余额字段内置在账户对象中,无需单独端点):

curl -s -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' \
  http://127.0.0.1:8146/1.0/kb/accounts/8fd8790e-44eb-41e1-8202-bcef9c3c8c20

实测回显(输出节选):

{
    "accountId": "8fd8790e-44eb-41e1-8202-bcef9c3c8c20",
    "name": "测试客户A",
    "externalKey": "8fd8790e-44eb-41e1-8202-bcef9c3c8c20",
    "email": "custa@example.com",
    "currency": "USD",
    "accountBalance": 0.0,
    "accountCBA": 0.0,
    "invoiceBalance": 0.0,
    "referenceTime": "2026-10-23T17:22:13.000Z"
}

关键字段解读:externalKey 是外部系统(你的业务库)与 Kill Bill 账户的关联键,创建时可自定、之后可用 GET /1.0/kb/accounts?externalKey=<key> 检索;accountBalance(账户总欠/余)、accountCBA(账户 Credit 余额)、invoiceBalance(未清发票合计)三值在对账时用途不同。

按外部键检索:

curl -s -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' \
  'http://127.0.0.1:8146/1.0/kb/accounts?externalKey=8fd8790e-44eb-41e1-8202-bcef9c3c8c20'

实测回显(数组返回单个账户,同上节选)。

5.2 支付方式(/1.0/kb/accounts/{id}/paymentMethods)

无真实网关时用内置的 __EXTERNAL_PAYMENT__ 插件(标记账户为外部收款,用于演示与线下转账场景):

curl -s -X POST 'http://127.0.0.1:8146/1.0/kb/accounts/8fd8790e-44eb-41e1-8202-bcef9c3c8c20/paymentMethods' \
  -u admin:q1w2e3r4 \
  -H 'Content-Type: application/json' \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  --data '{"pluginName":"__EXTERNAL_PAYMENT__","pluginInfo":{"externalPaymentMethodId":"custa-cc-001","isDefaultPaymentMethod":true}}' \
  -D - -o /dev/null

实测回显:

HTTP/1.1 201 Created
Location: http://127.0.0.1:8146/1.0/kb/paymentMethods/231f2bd7-5047-4157-bfec-45720b940fb5

⚠️ 排障实录:字段名写错会得到 400 并回显合法字段清单——本文实测把 externalPaymentMethodId 误写为 externalKey 时,错误体列出 PaymentMethodPluginDetailJson 仅接受 isDefaultPaymentMethod、properties、externalPaymentMethodId 三个字段,按清单修正即通过。这种「错误体自带字段白名单」的行为在 0.24.22 各写接口一致,是排除字段拼错的利器。

5.3 订阅管理(/1.0/kb/subscriptions)

开通订阅(planName 必须是目录中存在的计划):

curl -s -X POST 'http://127.0.0.1:8146/1.0/kb/subscriptions' \
  -u admin:q1w2e3r4 \
  -H 'Content-Type: application/json' \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  --data '{"accountId":"8fd8790e-44eb-41e1-8202-bcef9c3c8c20","planName":"standard-monthly"}' \
  -D - -o /dev/null

实测回显:

HTTP/1.1 201 Created
Location: http://127.0.0.1:8146/1.0/kb/subscriptions/bf0a2058-0747-4fb0-98c3-bae618842927

查询订阅状态:

curl -s -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' \
  http://127.0.0.1:8146/1.0/kb/subscriptions/bf0a2058-0747-4fb0-98c3-bae618842927

实测回显(输出节选):

{
    "subscriptionId": "bf0a2058-0747-4fb0-98c3-bae618842927",
    "productId": "ca05c725-36d8-4152-8c2e-6ba1a375d556",
    "planName": "standard-monthly",
    "state": "ACTIVE",
    "phaseType": "TRIAL",
    "billingPeriod": "MONTHLY",
    "priceList": "DEFAULT",
    "startDate": "2026-10-23T17:33:22.000Z"
}

standard-monthly 计划定义了 30 天试用期(TRIAL)+ 长期月费(EVERGREEN),刚开通处于 TRIAL 阶段,试用期结束自动转入 EVERGREEN 并按月出账。

取消订阅(DELETE,可选 JSON 控制即时/期末生效):

curl -s -X DELETE 'http://127.0.0.1:8146/1.0/kb/subscriptions/bf0a2058-0747-4fb0-98c3-bae618842927' \
  -u admin:q1w2e3r4 \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  -H 'Content-Type: application/json' \
  --data '{}'

实测回显(HTTP 204,再次查询状态):

HTTP/1.1 204 No Content
{"subscriptionId": "bf0a2058-0747-4fb0-98c3-bae618842927", "state": "CANCELLED", "cancelledDate": "2026-10-23T17:35:58.000Z"}

状态 CANCELLED 确认取消生效。请求体中带 "entitlementPolicyOverride":"IMMEDIATE" 可立即终止权益(默认按策略在计费周期末生效)。

5.4 发票管理(/1.0/kb/invoices 与 /1.0/kb/accounts/{id}/invoices)

查询账户全部发票:

curl -s -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' \
  http://127.0.0.1:8146/1.0/kb/accounts/8fd8790e-44eb-41e1-8202-bcef9c3c8c20/invoices

实测回显(输出节选,订阅开通即生成的试用期发票):

[
    {
        "invoiceId": "8991d4c4-5fab-4d32-afb3-50fae84a2c13",
        "invoiceNumber": "1",
        "status": "COMMITTED",
        "amount": 0.0,
        "balance": 0.0,
        "currency": "USD",
        "targetDate": "2026-10-23"
    }
]

账户 Credit(充值抵扣)(排障实录:端点是顶层 POST /1.0/kb/credits,请求体是数组,字段为 amount 而非 creditAmount):

curl -s -X POST 'http://127.0.0.1:8146/1.0/kb/credits' \
  -u admin:q1w2e3r4 \
  -H 'Content-Type: application/json' \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  --data '[{"accountId":"8fd8790e-44eb-41e1-8202-bcef9c3c8c20","amount": 100.00, "currency":"USD", "description":"预存赠送额度"}]'

实测回显(HTTP 200,返回生成的发票条目;CREDIT_ADJ 负项 + CBA_ADJ 正项记入一张草稿发票):

[
    {
        "invoiceId": "d7ae832d-381f-4aab-9164-9d01718c98de",
        "itemType": "CREDIT_ADJ",
        "amount": -100.0,
        "description": "预存赠送额度",
        "currency": "USD"
    }
]

该发票状态为 DRAFT(草稿),草稿发票不参与余额计算,需提交(POST /1.0/kb/invoices/{id}/commitInvoice)后生效——这是对账时「明明加了 Credit 但余额没变」的经典成因。

5.5 支付管理(/1.0/kb/invoices/{id}/payments)

对发票发起外部支付(账户已绑 __EXTERNAL_PAYMENT__ 支付方式时):

curl -s -X POST 'http://127.0.0.1:8146/1.0/kb/invoices/8991d4c4-5fab-4d32-afb3-50fae84a2c13/payments' \
  -u admin:q1w2e3r4 \
  -H 'Content-Type: application/json' \
  -H 'X-Killbill-ApiKey: bob' \
  -H 'X-Killbill-ApiSecret: lazar' \
  -H 'X-Killbill-CreatedBy: admin' \
  --data '{"accountId":"8fd8790e-44eb-41e1-8202-bcef9c3c8c20","purchasedAmount": 0.00, "paymentExternalKey": "inv1-pay-001"}'

实测回显(HTTP 204;Location 头返回支付记录地址):

HTTP/1.1 204 No Content

查询账户支付记录:

curl -s -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' \
  http://127.0.0.1:8146/1.0/kb/accounts/8fd8790e-44eb-41e1-8202-bcef9c3c8c20/payments

实测回显($0 试用期发票不产生实质支付记录,返回空数组;非零金额发票支付后会返回 purchasedAmount、status、transactions 等完整支付对象):

[]

💡 说明:真实网关场景下换装支付插件(Stripe/PayPal 等,经 OSGi 插件目录部署),同样的支付接口会路由到真实网关执行扣款;paymentExternalKey 是对账用的幂等键,请按业务生成唯一值。

5.6 租户与目录的其他常用端点

端点方法用途
/1.0/kb/tenantsPOST创建租户(4.1 实测 201)
/1.0/kb/catalogPOST/GET上传/查询目录(4.2/4.3 实测 201/200)
/1.0/kb/catalog/xmlGET取目录原始 XML
/1.0/kb/accounts/{id}/bundlesGET查账户契约包与订阅树
/1.0/kb/accounts/{id}/invoicesGET查账户发票(5.4 实测)
/1.0/kb/accounts/{id}/paymentsGET查账户支付(5.5 实测)
/1.0/kb/accounts/{id}/auditLogsGET查账户全量审计日志
/1.0/kb/invoices/{id}GET按发票 ID 查详情
/1.0/kb/invoices/{id}/commitInvoicePOST提交草稿发票
/1.0/kb/invoices/{id}/paymentsPOST发票收款(5.5 实测 204)
/1.0/kb/subscriptionsPOST开通订阅(5.3 实测 201)
/1.0/kb/subscriptions/{id}GET/DELETE查询/取消订阅(5.3 实测 200/204)
/1.0/kb/creditsPOST账户 Credit(5.4 实测 200)

六、分页与错误处理

6.1 分页约定(实测)

列表型接口支持 offset/limit 查询参数,分页元数据在响应头(不在响应体):

curl -s -D - -o /dev/null -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' \
  'http://127.0.0.1:8146/1.0/kb/accounts/pagination?offset=0&limit=5'

实测回显(分页相关响应头):

X-Killbill-Pagination-CurrentOffset: 0
X-Killbill-Pagination-TotalNbRecords: 1
X-Killbill-Pagination-MaxNbRecords: 1

体里是当前页数据数组;翻页用 offset 递增,TotalNbRecords 判断是否取完。同构分页面还有 /1.0/kb/invoices/pagination、/1.0/kb/payments/pagination 等。

6.2 错误体结构与常见码(实测)

错误响应是统一 JSON 结构(className/code/message):

查询不存在的账户(实测):

curl -s -u admin:q1w2e3r4 -H 'X-Killbill-ApiKey: bob' -H 'X-Killbill-ApiSecret: lazar' \
  http://127.0.0.1:8146/1.0/kb/accounts/00000000-0000-0000-0000-000000000000

实测回显:

{"className":"org.killbill.billing.util.callcontext.InternalCallContextFactory$ObjectDoesNotExist","code":null,"message":"Object id=00000000-0000-0000-0000-000000000000 type=ACCOUNT doesn't exist!","causeClassName":null,"causeMessage":null,"stackTrace":[]}

HTTP 状态码速查(全部为本文实测值):

状态码场景实测案例
200读接口/部分写接口成功GET catalog;POST credits
201资源创建成功创建账户/租户/订阅/支付方式
204成功且无返回体发票收款、取消订阅
400请求体字段非法支付方式字段拼写错误(错误体带合法字段清单)
401认证三件套缺失或错误缺 ApiKey 头
404资源不存在或端点不存在查询不存在的账户 ID;端点路径写错
415Content-Type 不符上传目录用 application/xml

七、常见问题

Q1:401 了,Basic 账号密码明明是对的? 认证三件套缺一不可(见第三节):Basic + ApiKey + ApiSecret。新部署还必须先创建租户(4.1),否则密钥头传什么都 401。

Q2:怎么判断订阅当前处于什么阶段? GET 订阅详情看 phaseType(TRIAL/DISCOUNT/FIXEDTERM/EVERGREEN)与 state(ACTIVE/CANCELLED/PENDING 等);阶段切换由目录定义与计费引擎自动推进,订阅变更走 POST /1.0/kb/subscriptions/{id}/changePlan。

Q3:调支付接口 400,提示 unknown properties? 错误体会列出该接口的合法字段白名单(本文 5.2/5.4 实测两次),对照修正字段名即可;注意 0.24.22 中支付请求需要 accountId + purchasedAmount。

Q4:加了 Credit 但账户余额没变? Credit 生成的是草稿发票(DRAFT),不参与余额计算,需提交(commitInvoice)生效;或者创建 Credit 时直接在账户上转余额(transferCredit 端点)。余额三值(accountBalance/invoiceBalance/accountCBA)的口径差异见 5.1 字段解读。

Q5:有没有命令行客户端? 官方早期有 kb-cli(Ruby gem),已多年未维护、未覆盖 0.24.x 新特性,不建议作为运维入口;REST API 是唯一覆盖全部能力的接口(本文即全部用 curl 实测),日常运营可配合 KAUI 界面与 Swagger 调试页。

Q6:哪里能看到全部端点与参数定义? 服务内置 Swagger 描述文件 http://<IP>:8146/swagger(OpenAPI 规范,可导入 Postman 生成客户端);本文表格收录的是运维高频端点,全部端点以 Swagger 为准。

八、参考链接

  1. 官方 API 文档(端点/参数定义):https://killbill.io/docs/
  2. Swagger 描述文件(服务内置):http://<服务器IP>:8146/swagger
  3. 官方 Getting Started(租户初始化与认证说明来源):https://docs.killbill.io/latest/getting_started.html
  4. 本平台同组件文档:《Kill Bill 0.24.22 介绍与选型指南》、《Kill Bill 0.24.22 Docker Compose 部署指南》、《Kill Bill 0.24.22 配置参数详解》