KeepPay 开发者文档
把卡数据攥回自己手里:在用户浏览器侧令牌化,明文永不落你的服务器;用令牌向任意能收卡的通道发起扣款,一套卡库对接谁都行。
Keep your data · Keep your choices · Keep your revenue
概述
KeepPay 是基于 PCI Level 1 合规底座的支付编排平台。集成只有三步:
- 前端采集 —— 用采集组件在用户浏览器把卡号换成令牌,明文不经过你的前后端。
- 首次支付 —— 后端使用令牌完成首次支付,并存进你名下的卡库(你只存令牌)。
- 用令牌扣款 —— 用令牌向支付通道中立转发发起扣款,明文在合规环境内还原注入,你的系统不碰 PAN。
API 基址:
快速开始
从令牌化一张测试卡到发起一笔扣款,最小闭环:
使用 Keeppay 托管的 Card iframe 采集卡号、有效期和 CVC。浏览器端只能使用具备 Card Token 创建权限的 Public Application Key,不要放入 Management Key 或 Private Key。
token.id 就是后端请求里的 token_id。Tokenization 只表示卡数据已被安全令牌化,
不代表付款成功;支付结果以后端调用 /api/payments 的响应为准。卡号、有效期和 CVC 始终保留在
Keeppay 托管 iframe 内。
以下示例直接调用测试环境。示例使用 Stripe 作为最终支付通道。
merchant_id、token_id、psp、
action,以及 stripe_request_params 中的 amount、
currency、confirm。续费时还应传
off_session:true、networkTransactionId;每笔业务订单使用唯一的
Idempotency-Key,同一笔请求重试时保持不变。
token_id、响应中的
network_transaction_id 和实际 psp。首付最终由 Stripe 或 Antom 完成均可继续续费。
核心概念
| 概念 | 说明 |
|---|---|
| 项目(应用) | 你的一个 App,一一对应。每个项目 = 一套前端公钥 / 后端私钥 / 授权域名;令牌、通道、计费都按项目归集。 |
| 令牌 Token(token_id) | 卡号令牌化后的引用。你只存令牌,明文在底座保险箱。 |
| 通道 Channel | 能用 API 收卡的 PSP( Stripe / Antom…)。用令牌向通道中立转发发起扣款。通道由 KeepPay 协助接通(见能力边界)。 |
| 环境 | 测试 / 正式,数据互相隔离。 |
名词不熟?查 出海支付术语表(编排 / 令牌化 / 网络令牌 / 软硬拒付 / MIT·CIT / 3DS / BIN…)。
鉴权与密钥
密钥按项目隔离,分三类,权限各不相同:
| 类型 | 用途 | 权限 | 放哪 |
|---|---|---|---|
| 前端公钥 | 采集组件 / 前端会话 | (只能创建令牌) | 可公开,放前端 |
| 后端私钥 | 服务器调用 API | keeppay分配,用于服务器端调用api | 商户保管,只放服务器 |
| PSP密钥 | 商户PSP端的密钥 | 商户用于请求PSP鉴权 | 商户保管 |
后端请求 header头中传入
pk_ 公钥(即使暴露也安全,权限仅创建令牌)。① 前端采集组件
Card 采集组件是由 Keeppay 托管的嵌入式 iframe。你的页面只负责加载 SDK、使用 Public Application Key 初始化组件并指定挂载位置;卡号、有效期和 CVC 不会进入你的页面 DOM 或服务器。
tokenId、提交后端并发起支付的完整流程请参见
快速开始;采集组件只在已配置的授权域名加载。
② 首次支付
前端取得 Card tokenId 后,由你的后端调用 KeepPay 完成首次支付。首次支付属于持卡人发起交易(CIT),
示例选择 Stripe,并通过 setup_future_usage:"off_session" 为后续离线续费建立使用条件。
X-KEEP-SIGN 用于 KeepPay 鉴权;Stripe 示例还需要
Authorization: Bearer sk_test_…。token_id 来自前端 Card Tokenization,
action 固定为 first_charge。同一笔订单重试时保持相同的
Idempotency-Key。
token_id、响应中的
network_transaction_id。无论首付由 Stripe 还是 Antom 完成,
这些数据都用于后续订阅续费;切换到 Antom 续费时必须提供首付 NTID(network_transaction_id)。
③ 令牌扣款与订阅续费
订阅到期后,使用首付保存的长期 token_id 发起离线续费(MIT),用户无需再次输入卡信息。
当前续费仍调用统一的 /api/payments,并通过 action:"recurring_charge" 标识续费。
续费通道与首付通道
首付最终由 Stripe 或 Antom 完成都可以续费。本次请求的 psp 决定实际续费通道:设置为
stripe 时读取 stripe_request_params;设置为 antom 时读取
antom_request_params。
off_session:true。Antom 续费必须在
antom_request_params.paymentMethod.paymentMethodMetaData.networkTransactionId 中传入首付保存的 NTID。
每一期续费使用新的业务订单号和幂等键;同一期因网络问题重试时保持幂等键不变。
令牌管理
令牌查询和删除都必须在请求头中传入 X-KEEP-SIGN。接口只接收或返回 Token 标识及安全的掩码信息,
不会把卡号、有效期或 CVC 明文返回给你的服务器。
读取令牌
token_id 是必填查询参数,填写前端 Tokenization 返回的 Token ID。
删除令牌
请求体中的 token_id 必填。删除成功后,该 Token 不能再用于首次支付或续费。
错误处理
所有 JSON 响应都会包含顶层字段 status 和 error_code。支付接口仍会在
params 中原样返回 Stripe 或 Antom 的官方响应,客户端应先检查顶层状态,再处理
params 中的支付状态或 3DS 信息。
{
"status": "error",
"error_code": "payment_failed",
"merchant_id": "merchant_001",
"psp": "stripe",
"params": {
"error": {
"message": "Your card was declined."
}
}
}
| HTTP | status | error_code | 含义 |
|---|---|---|---|
400 |
error |
具体参数校验错误信息 | 请求参数校验失败 |
402 |
error |
payment_failed |
PSP 返回支付失败;具体原因保留在 params |
403 |
error |
merchant_error / sign_error |
商户号有误或者密钥验证失败 |
404 |
error |
not_found |
接口或路由不存在 |
429 |
error |
rate_limited |
触发 Worker 限流 |
500 |
ok |
server_error |
内部异常 |
正常支付和需要进行 3DS 验证的支付都返回 HTTP 200、status:"ok"、
error_code:""。需要 3DS 时,请继续读取 params 中 PSP 官方返回的
status、next_action、跳转地址或验证表单。
上生产前必读
幂等键
对 /api/payments 请求带 Idempotency-Key 头(你生成的唯一串,建议使用订单号)。同一笔支付发生网络重试时保持相同 key,
返回首次结果。
限流
按应用限流;超限返回 429 + Retry-After 头,请指数退避重试。
超时与重试
支付请求超时后不要立即更换 PSP 重复扣款。先使用原 Idempotency-Key 重试或确认 PSP 最终状态,再决定是否切换通道。
API 参考
当前对外提供以下三个 API。点击端点可跳转到对应的参数或使用说明。
| 方法 | 端点 | 说明 |
|---|---|---|
| POST | /api/payments | 首次支付与订阅续费 |
| GET | /api/token/info?token_id=xxx | 查询令牌信息 |
| POST | /api/token/delete | 删除令牌 |
POST /api/payments
统一的首次支付和续费接口。Keeppay读取 psp 后,只把对应的 PSP 原生参数对象发送到该通道:
psp:"stripe" 使用 stripe_request_params,psp:"antom" 使用
antom_request_params。
请求头
| 参数 | 必填 | 说明 |
|---|---|---|
| X-KEEP-SIGN | 是 | KeepPay 商户请求签名。 |
| Content-Type | 是 | 固定为 application/json。 |
| Authorization | Stripe 必填 | Stripe 示例使用 Bearer sk_test_…;具体鉴权值由商户保管并提供。 |
| Idempotency-Key | 支付请求必填 | 每笔业务订单唯一;同一笔请求重试时保持不变。 |
公共请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| merchant_id | string | 是 | KeepPay 商户标识,用于加载商户配置。 |
| token_id | string | 是 | 前端 Card Tokenization 返回的长期 Token ID。 |
| payment | string | 否 | Card 场景固定传 card;未传时 Keeppay默认使用 card。 |
| psp | string | 是 | 本次实际支付通道:stripe 或 antom。 |
| action | string | 是 | 首次支付传 first_charge;续费传 recurring_charge。 |
| stripe_request_params | object | Stripe 必填 | Stripe PaymentIntent 原生参数对象,见下表。 |
| antom_request_params | object | Antom 必填 | Antom Pay 原生参数对象,见下表。 |
stripe_request_params
该对象按照 Stripe PaymentIntent 创建参数传递。完整字段、类型和约束以 Stripe Create a PaymentIntent 官方文档为准。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| amount | integer | 是 | 最小货币单位金额,例如 1990 表示 19.90 USD。 |
| currency | string | 是 | 三位小写货币代码,例如 usd。 |
| confirm | boolean | 是 | 示例固定为 true,创建后立即确认支付。 |
| payment_method_data.type | string | Token 支付必填 | Card Token 场景固定为 card;不要在该对象内提交卡号明文。 |
| setup_future_usage | string | 首付续费场景必填 | 首付传 off_session,表示计划后续离线使用。 |
| off_session | boolean | 续费必填 | 续费传 true,表示持卡人不在场。 |
| automatic_payment_methods | object | 否 | 续费可设置 enabled:true、allow_redirects:"never"。 |
| metadata | object | 否 | 业务元数据,建议传唯一交易号 trade_no。 |
| receipt_email | string | 否 | Stripe 支付收据邮箱。 |
| return_url | string | 按支付方式 | 仅在所选支付方式可能发生跳转时提供。 |
antom_request_params
该对象按照 Antom Pay 请求参数传递。完整字段、类型和地区差异以 Antom Pay 官方文档及 Antom Card/MIT 集成文档为准。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| productCode | string | 是 | 当前 Card 支付固定使用 CASHIER_PAYMENT。 |
| paymentRequestId | string | 是 | 商户生成的唯一支付请求号,也是 Antom 侧幂等标识。 |
| paymentAmount | object | 是 | {currency,value};币种使用大写,金额为最小货币单位字符串。 |
| settlementStrategy | object | 按商户配置 | 结算币种对象,例如 {settlementCurrency:"USD"}。 |
| paymentMethod | object | 是 | paymentMethodType 使用 CARD,卡数据由 Token 注入。 |
| paymentMethod.paymentMethodMetaData.isCardOnFile | string | 是 | 首付通常传 "false";续费传 "true"。 |
| paymentMethod.paymentMethodMetaData.tokenize | string | 首付按需 | 需要 Antom 保存后续使用信息时传 "true"。 |
| paymentMethod.paymentMethodMetaData.recurringType | string | 续费必填 | 定期订阅传 SCHEDULED,非固定周期可按官方规则使用 UNSCHEDULED。 |
| paymentMethod.paymentMethodMetaData.networkTransactionId | string | 续费必填 | 首付返回并保存的 NTID。 |
| order | object | 是 | 包含 referenceOrderId、orderDescription、orderAmount,可包含
buyer。
|
| paymentFactor | object | 是 | 当前 Card 授权请求使用 {isAuthorization:"true"}。 |
| env | object | 是 | 终端环境,例如 {terminalType:"WEB"},可按需传 clientIp。 |
| paymentRedirectUrl | string | 按支付流程 | 支付完成后的商户结果页地址。 |
| paymentNotifyUrl | string | 否 | Antom 异步支付结果通知地址。 |
安全与合规1
明文卡号在用户浏览器侧就换成令牌,不经过你的前后端;你的系统、日志、数据库里只有令牌,没有明文 PAN。
认证
| 认证 | 说明 |
|---|---|
| PCI DSS Level 1 | 最高等级支付卡合规(合规底座) |
| SOC 2 Type II | 安全 / 可用性控制审计 |
| ISO 27001 | 信息安全管理体系 |
| HIPAA | 敏感数据处理合规 |
安全特性
- 采集即令牌化 —— 卡号在采集点(浏览器侧)当场换令牌
- 端到端加密 —— 传输与存储全程加密
- 数据驻留 —— 按地区选择数据存放位置;企业版支持私有化部署
- 访问控制 + 审计日志 —— 谁能看明文 / 用令牌扣款 / 只读,按角色与容器规则;全量操作可审计
- PCI 范围收敛 —— 你的合规范围降到
SAQ A
能力边界与计费
白标
KeepPay 是中立平台,对接任意能用 API 收卡的 PSP。文档与你的集成中只出现 KeepPay 命名。
保险箱阶段的边界(诚实)
- 无交易语义:转发是无状态透传,KeepPay 不解析扣款成败、不记交易账本。成败 / 金额 / 拒付在通道响应 + 你的系统里。
- 通道平台级:通道(转发管线)由 KeepPay 协助接通(提交 PSP 凭证 → 我们配置 + AOC + 出站 IP 白名单,通常几天),不通过项目自助创建。
- 统一账本 / 智能路由 / 失败级联 / 智能重试 / AI 追回 / 报表属 KeepPay Flow即将上线 —— 卡已在你名下,升级零迁移。
- 本地非卡支付(钱包 / 转账)取决于所接 PSP,部分属路线图。
计费三计量
| 计量 | 口径 |
|---|---|
| 令牌存储费 | 按保存时长(token-天),按项目归集;删除的按「保存 → 删除」计入 |
| 令牌使用费 | 按支付请求次数(每次 /api/payments 计一次) |