如何在CyberSource中使用Flexible Token通过Payments API发起扣款?
我完全理解你的困惑——CyberSource的文档确实把令牌化和支付流程拆得比较开,没有直接给出整合后的示例。不过你并没有遗漏内容,只需要把Flexible Token替换掉Payments API里的卡信息字段就行,下面是具体的实现方案,包括Node.js的代码示例:
核心思路
当你通过Secure Acceptance Flexible Token API获取到令牌后,这个令牌(通常返回在paymentInstrument.token字段)可以直接替代Payments API请求中的卡号、CVV等敏感卡信息。只需要在请求体的paymentInformation节点下,用tokenizedCard对象包裹令牌,而不是使用card对象。
Node.js 实现方案(官方SDK)
使用CyberSource官方提供的cybersource-rest-client SDK是最简便的方式,它已经封装了认证和请求逻辑:
- 首先安装依赖:
npm install cybersource-rest-client
- 编写支付请求代码:
const cybersourceRestApi = require('cybersource-rest-client'); // 从CyberSource后台获取你的商户配置信息 const config = { authenticationType: 'http_signature', merchantID: 'YOUR_MERCHANT_ID', merchantKeyId: 'YOUR_API_KEY_ID', merchantSecretKey: 'YOUR_SECRET_KEY', runEnvironment: 'sandbox' // 生产环境改为 'production' }; const apiClient = new cybersourceRestApi.ApiClient(); apiClient.setConfiguration(config); const paymentsApi = new cybersourceRestApi.PaymentsApi(apiClient); // 构造支付请求,使用Flexible Token const paymentRequest = { clientReferenceInformation: { code: 'ORDER_12345' // 自定义订单编号 }, processingInformation: { capture: true, // true = 直接扣款;false = 预授权(后续需调用Capture API完成扣款) commerceIndicator: 'internet' }, paymentInformation: { tokenizedCard: { number: 'YOUR_FLEXIBLE_TOKEN', // 这里填入你获取到的Flex令牌 expirationMonth: '12', // 若令牌未包含过期信息,需传入原卡的过期月份 expirationYear: '2028' // 若令牌未包含过期信息,需传入原卡的过期年份 } }, orderInformation: { amountDetails: { totalAmount: '99.99', currency: 'USD' }, billTo: { firstName: 'Jane', lastName: 'Smith', address1: '456 Oak Ave', locality: 'San Francisco', administrativeArea: 'CA', postalCode: '94105', country: 'US', email: 'jane.smith@example.com' } } }; // 发起扣款请求 paymentsApi.createPayment(paymentRequest) .then(response => { console.log('支付成功:', JSON.stringify(response.data, null, 2)); }) .catch(error => { console.error('支付失败:', error.response.data); });
Node.js 实现方案(原生HTTP请求)
如果你不想依赖官方SDK,可以直接构造HTTP请求并处理签名:
const axios = require('axios'); const crypto = require('crypto'); const moment = require('moment'); // 配置信息 const merchantId = 'YOUR_MERCHANT_ID'; const apiKeyId = 'YOUR_API_KEY_ID'; const secretKey = 'YOUR_SECRET_KEY'; const baseUrl = 'https://apitest.cybersource.com'; // 生产环境改为 'https://api.cybersource.com' // 生成HTTP签名 function generateHmacSignature(method, path, payload) { const timestamp = moment().utc().format('YYYY-MM-DDTHH:mm:ss[Z]'); const digest = crypto.createHash('sha256').update(JSON.stringify(payload)).digest('base64'); const signingString = `${method}\n${path}\n${timestamp}\n${digest}\n`; const signature = crypto.createHmac('sha256', secretKey).update(signingString).digest('base64'); return `keyid="${apiKeyId}",algorithm="HmacSHA256",headers="host date request-target digest",signature="${signature}"`; } // 构造支付请求体 const paymentPayload = { clientReferenceInformation: { code: 'ORDER_67890' }, processingInformation: { capture: true, commerceIndicator: 'internet' }, paymentInformation: { tokenizedCard: { number: 'YOUR_FLEXIBLE_TOKEN', expirationMonth: '12', expirationYear: '2028' } }, orderInformation: { amountDetails: { totalAmount: '49.99', currency: 'EUR' }, billTo: { firstName: 'Pierre', lastName: 'Dubois', address1: '789 Rue de Paris', locality: 'Paris', postalCode: '75001', country: 'FR', email: 'pierre.dubois@example.com' } } }; const method = 'POST'; const path = '/pts/v2/payments/'; const timestamp = moment().utc().format('YYYY-MM-DDTHH:mm:ss[Z]'); const digest = crypto.createHash('sha256').update(JSON.stringify(paymentPayload)).digest('base64'); const signature = generateHmacSignature(method, path, paymentPayload); axios({ method, url: `${baseUrl}${path}`, headers: { 'Content-Type': 'application/json', 'Authorization': `Signature ${signature}`, 'Date': timestamp, 'Digest': `SHA-256=${digest}`, 'Host': 'apitest.cybersource.com', // 生产环境改为 'api.cybersource.com' 'Merchant-ID': merchantId }, data: paymentPayload }) .then(response => { console.log('支付成功:', response.data); }) .catch(error => { console.error('支付失败:', error.response.data); });
关键注意事项
- 令牌有效性:确保你的Flexible Token是由你的商户ID生成的,且未过期(测试环境令牌通常有效期较短)。
- 预授权流程:如果需要预授权,将
processingInformation.capture设为false,之后需要调用CaptureApi(或对应的HTTP端点)来完成实际扣款。 - 过期信息:部分Flex令牌会包含卡的过期信息,若返回结果中没有,必须传入原卡的过期月/年,否则请求会失败。
- 环境切换:测试环境(sandbox)和生产环境的API地址、密钥都是独立的,切换时要注意更新配置。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

