OmniCRM支付系统API指南
概述
OmniCRM支付系统提供了一个全面的、与供应商无关的支付处理基础设施。今天它支持Stripe和PayPal,但模块化架构允许与任何支付提供商(Square、Adyen、Braintree等)集成,而无需更改应用程序代码。
本文档涵盖了系统中所有可用的支付API和工作流程。
🔧 Ansible Playbook集成:有关在配置playbook中实现这些支付API的信息,请参见**从Playbooks进行收费和支付**
目录
模块化架构
为什么与供应商无关?
该系统使用抽象层将业务逻辑与支付供应商的具体细节分开。这意味着:
- ✅ 添加新的支付提供商而无需触及应用程序代码
- ✅ 切换供应商无需数据库迁移
- ✅ 同时支持多个供应商
- ✅ 无论后端提供商如何,API始终保持一致
架构层
添加新的支付供应商
要添加新的提供商(例如Square、Adyen、Braintree),请联系您的OmniCRM技术团队。
有关现有供应商(Stripe、PayPal)的配置详细信息,请参见**供应商配置**。
流程概述:
步骤:
- 实现处理器类,使用标准的
PaymentVendorInterface(授权、捕获、收费、退款、释放) - 在VendorFactory中注册处理器,使用供应商名称
- 在供应商的沙盒环境中测试集成
- 部署 - 所有现有API自动支持新供应商
结果:一旦部署,新供应商将无缝工作:
# 添加Square支付方式
curl -X POST /api/payments/methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"vendor": "square",
"payment_token": "sq_xxxxx"
}'
所有支付API自动支持新供应商,无需更改应用程序代码。
集成时间:通常需要1-2天来集成新的供应商处理器。
供应商配置
Stripe配置
Stripe是主要的支付供应商,提供带有3D安全支持的卡处理。
1. 获取Stripe API密钥
- 在 https://stripe.com 注册
- 导航到开发者 → API密钥
- 复制您的可发布密钥(pk_live_...或pk_test_...)
- 复制您的秘密密钥(sk_live_...或sk_test_...)
重要:
- 在开发中使用测试密钥(pk_test_/sk_test_)
- 仅在生产中使用实时密钥(pk_live_/sk_live_)
- 绝不要将API密钥提交到版本控制中
2. 配置后端
添加到crm_config.yaml:
payment_vendors:
stripe:
api_key: "sk_live_YOUR_SECRET_KEY_HERE"
publishable_key: "pk_live_YOUR_PUBLISHABLE_KEY_HERE"
或通过环境变量:
export STRIPE_SECRET_KEY="sk_live_YOUR_SECRET_KEY_HERE"
export STRIPE_PUBLISHABLE_KEY="pk_live_YOUR_PUBLISHABLE_KEY_HERE"
3. 配置前端
添加到.env:
REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_live_YOUR_PUBLISHABLE_KEY_HERE
安全注意:仅可发布密钥放在前端。秘密密钥绝不能暴露给浏览器。
PayPal配置
PayPal提供卡片保管和PayPal账户支付。
配置
添加到crm_config.yaml:
payment_vendors:
paypal:
client_id: "AXx_YOUR_CLIENT_ID_HERE"
client_secret: "ELx_YOUR_CLIENT_SECRET_HERE"
mode: "live" # 或 "sandbox" 用于测试
PCI合规性
OmniCRM如何维护PCI合规性:
- 卡数据直接输入到供应商托管的iframe中(Stripe Elements,PayPal Card Fields)
- OmniCRM从不查看或存储完整的卡号
- 仅在数据库中存储令牌化的支付方式
- 降低您业务的PCI合规性范围
支付处理指标
OmniCRM提供全面的指标来监控支付处理操作。有关Stripe支付指标的完整详细信息,包括API调用跟踪、支付量、失败率和响应时间,请参见监控与指标。
数据库架构与供应商无关
数据库架构支持任何支付供应商,无需迁移:
示例 - 保存Square卡:
{
"vendor": "square",
"vendor_payment_method_id": "sq_card_abc123",
"payment_type": "card"
}
无需代码更改。无需迁移。直接工作。
核心概念
数据模型
PaymentMethod
与供应商无关的客户支付方式存储。
{
"payment_method_id": 789,
"customer_id": 123,
"vendor": "stripe", // 'stripe', 'paypal'或任何添加的供应商
"vendor_payment_method_id": "pm_xxx", // 供应商的内部ID
"payment_type": "card", // 'card', 'paypal', 'ach'等
"is_default": true,
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2025,
"card_nickname": "My Visa Card",
"status": "active"
}
PaymentAuthorization
两阶段提交授权记录(保留资金)。
{
"authorization_id": 301,
"customer_id": 123,
"payment_method_id": 789,
"vendor": "stripe", // 哪个供应商授权
"vendor_authorization_id": "auth_xxx", // 供应商的授权ID
"amount": 200.00,
"currency": "USD",
"status": "authorized", // 'authorized', 'captured', 'released'
"authorized_at": "2025-12-27T10:00:00Z",
"expires_at": "2026-01-03T10:00:00Z",
"meta": {}
}
PaymentCapture
已捕获/完成的支付。
{
"capture_id": 103,
"authorization_id": 301,
"customer_id": 123,
"payment_method_id": 789,
"vendor": "stripe",
"vendor_transaction_id": "ch_xxx", // 供应商的交易ID
"amount": 200.00,
"currency": "USD",
"status": "succeeded", // 'succeeded', 'failed', 'refunded'
"captured_at": "2025-12-27T10:30:00Z",
"vendor_response": {}, // 完整的供应商响应
"meta": {}
}
WalletAccount
客户钱包及余额跟踪(与客户一对一)。
{
"wallet_account_id": 456,
"customer_id": 123,
"balance": 150.50,
"currency": "USD",
"auto_recharge_enabled": true,
"auto_recharge_amount": 100.00,
"auto_recharge_threshold": 10.00,
"low_balance_warning_threshold": 10.00
}
WalletLedger
所有钱包交易的完整审计记录。
{
"ledger_id": 501,
"customer_id": 123,
"wallet_account_id": 456,
"transaction_type": "credit", // 'credit', 'debit', 'refund', 'adjustment'
"amount": 100.00,
"balance_before": 150.50,
"balance_after": 250.50,
"currency": "USD",
"description": "Card top-up",
"reference_type": "payment_capture", // 链接到相关对象
"reference_id": 103,
"meta": {},
"created_at": "2025-12-27T10:35:00Z"
}
财务文件
有关发票模板和自定义的信息,请参见**客户发票**。
发票
定义:发票是包含借记交易(收费)列表的文档。当调用API创建发票时,应提供借记交易ID的数组。通过设置它们的invoice_id字段,这些交易与发票“链接”。
有关交易管理的详细信息,请参见**交易**。
关键字段:
{
"invoice_id": 12345,
"invoice_number": "INV-2025-000001", // 自动生成:INV-YYYY-NNNNNN
"customer_id": 123,
"title": "每月服务发票",
"paid": true, // 支付状态
"void": false, // 作废状态
"payment_reference": "ch_xxxxx", // 最后/主要支付ID
"payment_type": "stripe_capture", // 最后支付类型
"payment_time": "2025-12-27T10:30:00",
"start_date": "2025-12-01",
"end_date": "2025-12-31",
"due_date": "2026-01-15",
"retail_cost": 500.00, // 发票总金额
"wholesale_cost": 250.00
}
发票生成:发票编号以INV-YYYY-NNNNNN格式自动生成,在日历年内按顺序生成,每年1月1日重置。
发票上的支付
支付如何工作:一旦从借记交易创建了发票,可以通过创建与发票相关联的信用交易(负的retail_cost)来应用支付。
支付应:
- 清楚地列在发票上,标记为“支付”
- 显示相关的支付日期(可以与发票创建日期不同)
- 支持每张发票的多个支付
- 净额与借记相抵消以计算发票余额
发票状态:
- 已支付:总支付(信用)等于或超过总借记
- 部分支付:已应用一些支付,但余额仍然存在
- 超额支付:当前不处理 - 需要信用拆分(未来功能)
复式记账:系统实现了适当的会计,每个收费都有相应的支付:
// 1. 借记交易(收费)
{
"transaction_id": 7001,
"invoice_id": 12345,
"retail_cost": 100.00, // 正数 = 客户欠款
"title": "服务费"
}
// 2. 信用交易(支付)
{
"transaction_id": 7002,
"invoice_id": 12345,
"retail_cost": -100.00, // 负数 = 收到支付
"title": "发票支付:服务费(12345)",
"payment_type": "stripe_capture",
"payment_reference": "ch_xxxxx"
}
// 净结果:$0余额 → 发票标记为已支付
补充发票元数据:除了信用交易外,发票还存储摘要字段(payment_reference、payment_type、payment_time)以便快速查找。然而:
- 主要方法:通过
invoice_id链接的信用交易(Hayden的规范) - 次要元数据:发票字段存储最后/主要支付的摘要
- 对于多个支付:查询信用交易以获取完整历史
对账单
定义:对账单显示客户在指定期间内的所有借记和信用交易。这是唯一一种同时显示借记和信用作为行项目的文档类型,就像银行对账单一样。
信用票据
目的:仅适用于已经应用支付的发票。必须作为发票作废过程的一部分进行。
流程:
- 发票被作废(连同其相关的借记交易)
- 任何已应用的支付与创建的信用票据关联
- 客户的余额按等额金额进入信用
- 信用票据余额可以:
- 作为支付应用于另一张发票,或
- 退款给客户
退款逻辑:如果选择退款,则根据相关的信用交易及其最初的支付方式(例如,如果信用交易类型为Stripe,则进行Stripe退款)进行调用。
支付方式API
所有端点使用基本URL:/api/payments/
有关详细的支付方式管理和卡处理,请参见**支付方式**。
添加支付方式
为客户保存新的支付方式。
端点:POST /api/payments/methods
请求:
curl -X POST https://your-domain.com/api/payments/methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"is_default": false,
"card_nickname": "My Visa Card"
}'
请求体:
{
"customer_id": 123,
"vendor": "stripe", // 'stripe', 'paypal'或任何添加的供应商
"payment_token": "pm_xxxxx", // 前端SDK生成的一次性令牌
"is_default": false, // 设置为默认支付方式?
"card_nickname": "My Visa Card" // 可选的友好名称
}
响应(201已创建):
{
"success": true,
"message": "支付方式添加成功",
"data": {
"payment_method_id": 789,
"customer_id": 123,
"vendor": "stripe",
"payment_type": "card",
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2025,
"card_nickname": "My Visa Card",
"is_default": false,
"status": "active"
}
}
获取支付方式
检索客户的所有支付方式。
端点:GET /api/payments/methods?customer_id={id}
请求:
curl -X GET "https://your-domain.com/api/payments/methods?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
响应(200 OK):
{
"success": true,
"data": [
{
"payment_method_id": 789,
"customer_id": 123,
"vendor": "stripe",
"payment_type": "card",
"card_brand": "visa",
"card_last4": "4242",
"is_default": true
},
{
"payment_method_id": 790,
"customer_id": 123,
"vendor": "paypal",
"payment_type": "paypal",
"paypal_email": "user@example.com",
"is_default": false
}
]
}
获取默认支付方式
获取客户的默认支付方式。
端点:GET /api/payments/methods/default?customer_id={id}
请求:
curl -X GET "https://your-domain.com/api/payments/methods/default?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
响应(200 OK):
{
"success": true,
"data": {
"payment_method_id": 789,
"vendor": "stripe",
"payment_type": "card",
"card_brand": "visa",
"card_last4": "4242",
"is_default": true
}
}
设置默认支付方式
将支付方式设置为默认。
端点:PUT /api/payments/methods/set-default
请求:
curl -X PUT https://your-domain.com/api/payments/methods/set-default \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"payment_method_id": 790
}'
响应(200 OK):
{
"success": true,
"message": "默认支付方式已更新",
"data": {
"payment_method_id": 790,
"is_default": true
}
}
删除支付方式
删除已保存的支付方式。
端点:DELETE /api/payments/methods/{payment_method_id}?customer_id={id}
请求:
curl -X DELETE "https://your-domain.com/api/payments/methods/789?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
响应(200 OK):
{
"success": true,
"message": "支付方式删除成功"
}
支付流程API
该系统支持多种支付流程,具体取决于您的用例。
1. 直接支付(简单收费)
用例:简单的一步支付,无需服务提供。
端点:POST /api/payments/charge
请求:
curl -X POST https://your-domain.com/api/payments/charge \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 50.00,
"currency": "USD",
"payment_method_id": 789,
"metadata": {
"order_id": "12345"
}
}'
请求体:
{
"customer_id": 123,
"amount": 50.00,
"currency": "USD", // 默认:USD
"payment_method_id": 789, // 可选 - 如果省略则使用默认
"vendor": "stripe", // 如果使用payment_token则必需
"payment_token": "pm_xxxxx", // 可选 - 一次性令牌
"save_method": false, // 保存支付方式以供将来使用?
"metadata": {
"order_id": "12345"
}
}
响应(200 OK):
{
"success": true,
"message": "支付成功",
"data": {
"transaction_id": "ch_xxxxx",
"capture_id": 101,
"amount": 50.00,
"currency": "USD",
"status": "succeeded"
}
}
2. 发票支付(优先使用钱包)
用例:使用钱包余额支付发票,剩余部分使用卡支付。
端点:POST /api/payments/invoice
流程:
- 检查钱包余额
- 首先使用钱包资金
- 对短缺部分收取卡���(如有)
- 用卡金额信用钱包
- 从钱包中借记全额发票金额
请求:
curl -X POST https://your-domain.com/api/payments/invoice \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 200.00,
"payment_method_id": 789,
"metadata": {
"invoice_id": 12345,
"description": "发票支付"
}
}'
响应(200 OK):
{
"success": true,
"message": "发票支付已处理",
"data": {
"customer_id": 123,
"service_amount": 200.00,
"routing_mode": "hybrid",
"initial_balance": 150.00,
"wallet_portion_used": 150.00, // 钱包覆盖了这部分
"card_portion_used": 50.00, // 卡收取剩余部分
"charged_amount": 50.00,
"wallet_credited": 50.00,
"wallet_debited": 200.00,
"final_balance": 0.00,
"payment_method_used": true
}
}
3. 授权保留(保留资金)
用例:为后续捕获保留资金(例如,酒店预订、租赁)。
🔧 Playbook实现:有关两阶段支付流程的Ansible playbook示例,请参见两阶段提交模式
第1步:创建授权保留
端点:POST /api/payments/authorize/hold
优先使用钱包流程:
- 检查钱包余额
- 计算短缺(金额 - 钱包余额)
- 仅对短缺部分授权卡
- 钱包借记在捕获时发生,而不是在此时
请求:
curl -X POST https://your-domain.com/api/payments/authorize/hold \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 200.00,
"payment_method_id": 789,
"use_wallet": true,
"metadata": {
"reservation_id": "RES-001"
}
}'
请求体:
{
"customer_id": 123,
"amount": 200.00,
"currency": "USD",
"payment_method_id": 789, // 可选 - 如果省略则使用默认
"vendor": "stripe", // 如果使用payment_token则必需
"payment_token": "pm_xxxxx", // 可选 - 一次性令牌
"save_method": false,
"use_wallet": true, // 启用优先使用钱包路由(默认:true)
"metadata": {
"reservation_id": "RES-001"
}
}
响应(200 OK):
{
"success": true,
"message": "支付已授权(创建了保留)",
"data": {
"authorization_id": 301,
"vendor_authorization_id": "auth_xxxxx",
"amount": 200.00,
"currency": "USD",
"status": "authorized",
"wallet_balance": 150.00,
"wallet_to_use": 150.00, // 钱包将覆盖这部分
"card_amount": 50.00, // 卡授权这部分
"message": "卡授权$50(钱包充值)。在捕获时将发生$200的借记。"
}
}
第2步:捕获授权
端点:POST /api/payments/capture/{authorization_id}
优先使用钱包捕获流程:
- 捕获卡(如果已授权) - 顶替钱包
- 用捕获的卡金额信用钱包
- 从钱包中借记全额服务金额
- 创建发票/交易(如请求)
请求:
curl -X POST https://your-domain.com/api/payments/capture/301 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"amount": 200.00,
"metadata": {
"invoice": true,
"title": "酒店预订",
"description": "3晚住宿",
"wholesale_cost": 100.00,
"contract_days": 3,
"send_email": true
}
}'
请求体:
{
"amount": 200.00, // 可选 - 如果省略则捕获全额
"metadata": {
"invoice": true, // 创建发票和交易记录?
"create_transaction": true, // 创建交易记录?
"title": "酒店预订",
"description": "3晚住宿",
"wholesale_cost": 100.00,
"contract_days": 3,
"send_email": true // 发送发票电子邮件?
}
}
响应(200 OK):
{
"success": true,
"message": "授权已捕获",
"data": {
"capture_id": 103,
"transaction_id": "ch_xxxxx",
"authorization_id": 301,
"amount": 200.00,
"currency": "USD",
"status": "succeeded",
"wallet_credit": { // 卡充值钱包
"ledger_id": 401,
"amount": 50.00
},
"wallet_debit": { // 服务从钱包中收取
"ledger_id": 402,
"amount": 200.00
},
"transaction": { // 如果invoice=true则创建
"transaction_id": 7001
},
"invoice": { // 如果invoice=true则创建
"invoice_id": 12345,
"invoice_number": "INV-2025-000001"
}
}
}
第3步:释放授权(取消)
端点:POST /api/payments/release/{authorization_id}
用例:取消预订、提供失败或客户改变主意。
请求:
curl -X POST https://your-domain.com/api/payments/release/301 \
-H "Authorization: Bearer YOUR_API_KEY"
响应(200 OK):
{
"success": true,
"message": "授权已释放",
"data": {
"authorization_id": 301,
"vendor_authorization_id": "auth_xxxxx",
"status": "released",
"released_at": "2025-12-27T10:45:00Z"
}
}
注意:使用优先使用钱包流程时,无需钱包退款,因为钱包在捕获时才会借记。
4. 充值支付(两阶段与提供)
用例:处理需要提供的服务充值支付(例如,热点/加密狗激活)。如果提供失败,则释放授权。
端点:POST /api/payments/topup
流程:授权 → 提供服务 → 捕获
请求:
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 30.00,
"payment_method_id": 789,
"service_uuid": "svc-uuid-123",
"imsi": "123456789012345",
"days": 30,
"metadata": {
"is_rental": false
}
}'
对于匿名租赁/热点(支付方式未保存):
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 1,
"amount": 5.00,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"service_uuid": "hotspot-uuid",
"imsi": "123456789012345",
"days": 1,
"metadata": {
"is_rental": true,
"billing_email": "user@example.com"
}
}'
响应(200 OK):
{
"success": true,
"message": "充值支付处理成功",
"data": {
"transaction_id": "ch_xxxxx",
"authorization_id": 302,
"capture_id": 104,
"amount": 30.00,
"status": "succeeded",
"provision_result": {
"success": true,
"topup_result": {...},
"service_uuid": "svc-uuid-123",
"imsi": "123456789012345",
"days": 30
},
"payment_method_saved": false // 匿名/租赁为false
}
}
5. 租赁支付(第三方)
用例:向一位客户的卡收费以支付另一位客户的服务。
端点:POST /api/payments/rental
请求:
curl -X POST https://your-domain.com/api/payments/rental \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"beneficiary_customer_id": 456,
"charge_customer_id": 123,
"amount": 75.00,
"payment_method_id": 789,
"service_description": "租赁服务支付",
"metadata": {
"rental_agreement_id": "RA-001"
}
}'
对于匿名租赁(租赁者的卡未保存):
curl -X POST https://your-domain.com/api/payments/rental \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"beneficiary_customer_id": 456,
"amount": 75.00,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"service_description": "匿名租赁支付",
"metadata": {
"billing_email": "renter@example.com"
}
}'
响应(200 OK):
{
"success": true,
"message": "租赁支付处理成功",
"data": {
"transaction_id": "ch_xxxxx",
"amount": 75.00,
"payment_method_saved": false // 匿名:未保存方法
}
}
6. 退款支付
端点:POST /api/payments/refund
请求:
curl -X POST https://your-domain.com/api/payments/refund \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"transaction_id": "ch_xxxxx",
"vendor": "stripe",
"amount": 50.00,
"reason": "customer_request"
}'
请求体:
{
"transaction_id": "ch_xxxxx", // 供应商交易ID
"vendor": "stripe", // 'stripe', 'paypal'等
"amount": 50.00, // 可选 - 如果省略则全额退款
"reason": "customer_request" // 可选退款原因
}
响应(200 OK):
{
"success": true,
"message": "退款处理成功",
"data": {
"refund_id": "re_xxxxx",
"amount": 50.00,
"status": "succeeded"
}
}
钱包API
所有钱包端点使用基本URL:/api/wallet/
获取钱包余额
端点:GET /api/wallet/balance?customer_id={id}
请求:
curl -X GET "https://your-domain.com/api/wallet/balance?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
响应(200 OK):
{
"customer_id": 123,
"balance": 150.50,
"currency": "USD"
}
获取钱包信息
获取完整的钱包和信用信息,包括自动充值设置。
端点:GET /api/wallet/info?customer_id={id}
请求:
curl -X GET "https://your-domain.com/api/wallet/info?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
响应(200 OK):
{
"customer_id": 123,
"wallet": {
"wallet_account_id": 456,
"balance": 150.50,
"currency": "USD",
"auto_recharge_enabled": true,
"auto_recharge_amount": 100.00,
"auto_recharge_threshold": 10.00,
"low_balance_warning_threshold": 10.00
}
}
钱包充值
通过收费支付方式为钱包充值。
端点:POST /api/wallet/topup
流程:收费卡/PayPal → 信用钱包
请求:
curl -X POST https://your-domain.com/api/wallet/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 100.00,
"payment_method_id": 789
}'
请求体:
{
"customer_id": 123,
"amount": 100.00,
"currency": "USD", // 默认:USD
"payment_method_id": 789 // 可选 - 如果省略则使用默认
}
响应(200 OK):
{
"success": true,
"payment": {
"transaction_id": "ch_xxxxx",
"amount": 100.00
},
"wallet": {
"ledger_id": 503,
"balance_after": 250.50
},
"message": "钱包充值100.00美元成功"
}
获取钱包交易
获取钱包交易历史(账本)。
端点:GET /api/wallet/transactions?customer_id={id}&limit={n}&offset={n}&type={type}
请求:
curl -X GET "https://your-domain.com/api/wallet/transactions?customer_id=123&limit=50&offset=0&type=credit" \
-H "Authorization: Bearer YOUR_API_KEY"
查询参数:
customer_id(必需):客户IDlimit(可选):记录数量(默认:50)offset(可选):分页偏移(默认:0)type(可选):按交易类型过滤('credit','debit','refund','adjustment')
响应(200 OK):
{
"customer_id": 123,
"count": 2,
"transactions": [
{
"ledger_id": 501,
"transaction_type": "credit",
"amount": 100.00,
"balance_before": 150.50,
"balance_after": 250.50,
"description": "卡充值",
"reference_type": "payment_capture",
"reference_id": 103,
"created_at": "2025-12-27T10:35:00Z"
},
{
"ledger_id": 502,
"transaction_type": "debit",
"amount": 50.00,
"balance_before": 250.50,
"balance_after": 200.50,
"description": "服务收费",
"reference_type": "service_charge",
"reference_id": 789,
"created_at": "2025-12-27T11:00:00Z"
}
]
}
API参考摘要
支付方式端点
| 方法 | 端点 | 描述 |
|---|---|---|
| POST | /api/payments/methods | 添加支付方式 |
| GET | /api/payments/methods?customer_id={id} | 获取所有支付方式 |
| GET | /api/payments/methods/default?customer_id={id} | 获取默认支付方式 |
| PUT | /api/payments/methods/set-default | 设置默认支付方式 |
| DELETE | /api/payments/methods/{id}?customer_id={id} | 删除支付方式 |
支付流程端点
| 方法 | 端点 | 描述 |
|---|---|---|
| POST | /api/payments/charge | 直接支付(一步) |
| POST | /api/payments/invoice | 发票支付(优先使用钱包) |
| POST | /api/payments/topup | 充值与提供 |
| POST | /api/payments/authorize/hold | 创建授权保留 |
| POST | /api/payments/capture/{id} | 捕获授权 |
| POST | /api/payments/release/{id} | 释放授权 |
| POST | /api/payments/rental | 租赁/第三方支付 |
| POST | /api/payments/refund | 退款支付 |
钱包端点
| 方法 | 端点 | 描述 |
|---|---|---|
| GET | /api/wallet/balance?customer_id={id} | 获取钱包余额 |
| GET | /api/wallet/info?customer_id={id} | 获取钱包信息 + 设置 |
| POST | /api/wallet/topup | 通过支付方式为钱包充值 |
| GET | /api/wallet/transactions?customer_id={id} | 获取交易历史 |
PayPal特定端点
| ���法 | 端点 | 描述 |
|---|---|---|
| POST | /api/payments/paypal/vault/setup-token | 为Card Fields SDK创建PayPal设置令牌 |
| POST | /api/payments/paypal/vault/finalize | 完成PayPal保管并保存支付方式 |
| POST | /api/payments/paypal/vault/update-setup-token | 更新3DS/SCA处理的设置令牌 |
常见用例
用例1:向客户收费(预付)
场景:客户使用优先使用钱包路由支付30天的服务。
# 发票支付(优先使用钱包,卡支付短缺部分)
curl -X POST https://your-domain.com/api/payments/invoice \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 99.99,
"metadata": {
"service_id": 456,
"contract_days": 30,
"description": "30天高级服务"
}
}'
响应:
{
"success": true,
"message": "发票支付已处理",
"data": {
"service_amount": 99.99,
"wallet_portion_used": 50.00, // 钱包有$50
"card_portion_used": 49.99, // 卡收取$49.99
"final_balance": 0.00
}
}
用例2:两阶段支付与服务提供
场景:仅在支付被授权后提供服务。如果提供失败,则不收���费用。
# 充值支付与自动提供
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 149.99,
"payment_method_id": 789,
"service_uuid": "fiber-svc-uuid",
"imsi": "123456789012345",
"days": 30,
"metadata": {
"service_type": "fiber_internet"
}
}'
流程:
- 在卡上授权$149.99
- 提供光纤互联网服务
- 如果提供成功 → 捕获支付
- 如果提供失败 → 释放授权(不收费)
用例3:热点匿名支付
场景:匿名用户支付WiFi热点访问费用。没有客户记录,没有保存的支付方式。
# 匿名热点支付
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 1,
"amount": 5.00,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"service_uuid": "hotspot-downtown",
"imsi": "999999999999999",
"days": 1,
"metadata": {
"is_rental": true,
"billing_email": "user@example.com",
"hotspot_location": "市中心咖啡馆"
}
}'
结果:
- 支付处理成功 ✅
- 热点已激活 ✅
- 支付方式未保存 ✅
- 未创建客户记录 ✅
用例4:酒店预订(授权保留 + 捕获)
场景:为酒店预订保留资金,入住时捕获,取消时释放。
# 第1步:入住 - 保留资金
curl -X POST https://your-domain.com/api/payments/authorize/hold \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 500.00,
"use_wallet": true,
"metadata": {
"reservation_id": "RES-2025-001"
}
}'
# 响应:{"authorization_id": 301, "status": "authorized"}
# 第2a步:客户入住 - 捕获
curl -X POST https://your-domain.com/api/payments/capture/301 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"metadata": {
"invoice": true,
"title": "酒店住宿 - 3晚",
"description": "302房间,12月27日至30日",
"send_email": true
}
}'
# 第2b步:客户取消 - 释放保留
curl -X POST https://your-domain.com/api/payments/release/301 \
-H "Authorization: Bearer YOUR_API_KEY"
用例5:添加支付方式(Stripe)
场景:客户向其账户添加新的Visa卡。
# 第1步:前端通过Stripe.js创建Stripe令牌
# const {token} = await stripe.createToken(cardElement);
# 第2步:后端保存支付方式
curl -X POST https://your-domain.com/api/payments/methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"is_default": true,
"card_nickname": "工作Visa"
}'
用例6:钱包充值
场景:客户使用保存的支付方式为其钱包充值$100。
curl -X POST https://your-domain.com/api/wallet/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 100.00
}'
响应:
{
"success": true,
"payment": {
"transaction_id": "ch_xxxxx",
"amount": 100.00
},
"wallet": {
"balance_after": 250.50
},
"message": "钱包充值100.00美元成功"
}
错误处理
常见错误响应
资金不足(400错误请求):
{
"error": "钱包余额不足。可用:50.00,所需:200.00"
}
支付失败(400错误请求):
{
"error": "支付失败。请再试一次。"
}
验证错误(400错误请求):
{
"error": "customer_id和amount是必需的"
}
未找到(404未找到):
{
"error": "授权999未找到"
}
服务器错误(500内部服务器错误):
{
"error": "处理您的支付时发生错误"
}
退款与优先使用钱包
退款选项
系统支持两种退款类型,具体取决于您的业务需求:
1. 退款到支付来源(Stripe/PayPal)
用例:客户请求因取消服务或缺陷产品而全额退款。
流程:资金返回到原始支付方式(卡、PayPal账户等)。
端点:POST /api/payments/refund
示例:
curl -X POST https://your-domain.com/api/payments/refund \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"transaction_id": "ch_xxxxx",
"vendor": "stripe",
"amount": 100.00,
"reason": "customer_request"
}'
结果:
- Stripe/PayPal处理退款到原始支付方式
- 客户在5-10个工作日内看到其卡/PayPal账户的信用
- 资金不进入钱包
- 在
PaymentCapture表中维护完整的审计记录
何时使用:
- ✅ 客户取消订单
- ✅ 服务未交付
- ✅ 计费错误
- ✅ 客户明确请求退款到卡
2. 信用到钱包
用例:部分退款、服务信用或保留资金以供未来购买。
注意:钱包信用通常在错误场景中由系统内部处理。有关手动钱包信用的信息,请联系支持或使用管理工具。
结果:
- 资金立即可用于钱包
- 无等待期
- 可用于未来购买
- 在
WalletLedger表中维护完整的审计记录
何时使用:
- ✅ 服务信用(例如,因停机而补偿)
- ✅ 客户将重新购买的部分退款
- ✅ 错误补偿(提供失败)
- ✅ 促销信用
混合退款策略
最佳实践:在支付流程中的错误场景下,系统自动将信用转入钱包,而不是退款到卡。
自动错误恢复:
示例场景:
- 客户支付$100以获取服务
- 卡成功收费
- 提供失败
- 不退款$100到卡(5-10天 + 退款费用):
- 立即信用$100到钱包
- 客户可以立即重试购买
- 无退款���用
- 更好的用户体验
优先使用钱包路由:优化卡收费
系统仅对短缺部分收费,而不是全额,当您有钱包余额时。
示例1:$1钱包余额 + $10购买
场景:您钱包中有$1,想购买$10的附加服务。
传统支付流程(不是该系统的工作方式):
OmniCRM优先使用钱包流程:
API请求:
curl -X POST https://your-domain.com/api/payments/invoice \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 10.00,
"metadata": {
"addon_id": 456
}
}'
API响应:
{
"success": true,
"message": "发票支付已处理",
"data": {
"customer_id": 123,
"service_amount": 10.00,
"routing_mode": "hybrid",
"initial_balance": 1.00,
"wallet_portion_used": 1.00, // 使用现有的$1
"card_portion_used": 9.00, // 仅收费$9短缺
"charged_amount": 9.00, // ← 卡收费
"wallet_credited": 9.00, // ← 充值钱包
"wallet_debited": 10.00, // ← 服务费用
"final_balance": 0.00
}
}
示例2:$50钱包余额 + $30购买
场景:您钱包中有$50,购买费用为$30。
优先使用钱包流程:
API响应:
{
"success": true,
"data": {
"service_amount": 30.00,
"initial_balance": 50.00,
"charged_amount": 0, // ← 无卡收费
"wallet_debited": 30.00,
"final_balance": 20.00,
"payment_method_used": false // ← 未使用卡
}
}
示例3:授权保留与钱包余额
场景:酒店保留$500的授权,钱包余额为$150。
第1步:授权(POST /api/payments/authorize/hold):
API响应:
{
"authorization_id": 301,
"amount": 500.00,
"status": "authorized",
"wallet_balance": 150.00,
"wallet_to_use": 150.00,
"card_amount": 350.00,
"message": "卡授权$350(钱包充值)。在捕获时将发生$500的借记。"
}
第2步:捕获(POST /api/payments/capture/301):
这很重要:
- ✅ 客户仅对其卡保留$350,而不是$500
- ✅ 减少客户可用信用的影响
- ✅ 更准确的授权金额
- ✅ 更好的客户体验
实施细节
优先使用钱包路由逻辑:
工作原理:
- 系统检查当前钱包余额
- 计算短缺:
金额 - 钱包余额 - 如果短缺 > 0,则仅对短缺部分收费
- 用卡支付金额信用钱包
- 借记钱包全额服务金额
- 结果:客户仅为钱包无法覆盖的部分收费
路由模式覆盖
如果需要,您可以覆盖优先使用钱包的行为:
绕过模式 - 即使钱包有资金也始终收费卡:
curl -X POST https://your-domain.com/api/payments/charge \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 100.00,
"metadata": {
"routing_mode": "bypass"
}
}'
结果:卡收费$100,钱包信用$100,钱包借记$100(净:$0)
用例:客户希望使用卡以获取奖励/积分,即使有钱包余额。
最佳实践
- 始终使用优先使用钱包路由进行客户支付,以启用预付功能
- 在提供服务时使用两阶段支付(充值端点),以避免在提供失败时收费
- 为所有支付设置元数据以维护审计记录
- 仅对真正匿名用户使用匿名支付(热点、租赁)
- 优雅地处理错误并提供清晰的用户反馈
- 测试支付流程以确保成功和失败场景
- 监控授权过期(通常为卡的7天)
- 实施自动充值以改善客户体验
Playbook特定最佳实践
在Ansible playbook中实现支付流程时:
- 始终使用块/救援模式 - 将提供包装在try/catch中以实现自动回滚
- 存储authorization_id - 保存以供捕获/释放操作
- 验证API响应 - 在继续之前断言成功
- 四舍五入货币值 - 始终使用2位小数
- 检查支付方式 - 在授权之前验证客户是否有默认支付方式
有关完整详细信息和示例,请参见Playbook最佳实践。
身份验证
所有API端点都需要通过API密钥进行身份验证,密钥应放在Authorization头中:
Authorization: Bearer YOUR_API_KEY
请联系您的系统管理员以获取API密钥。
供应商支持
当前支持
- Stripe - 完全支持(卡、ACH)
- PayPal - 完全支持(PayPal账户、通过Card Fields SDK的卡)
添加新供应商
模块化架构使添加新的支付供应商变得简单。有关详细信息,请参见模块化架构部分。
相关文档
实施指南
- 从Playbooks进行收费和支付 - Ansible playbook实施
特性特定指南
快速导航
- 添加供应商? → 请参见模块化架构
- 配置Stripe/PayPal? → 请参见供应商配置
- 自定义发票? → 请参见客户发票
- 提供服务? → 请参见Playbook集成