如何获取 Sage Pay repeat payment API?
结论
Sage Pay 的 repeat payment 通常不需要下载单独的 PHP API 或 SDK,而是向网关提交 REPEAT 类型的交易。你需要先完成一笔初始交易,并在交易成功后保存 Sage Pay 返回的交易标识和安全信息,用于发起后续扣款。
Sage Pay 现已更名为 Opayo。不同接入方式和协议版本使用的接口地址及字段要求可能不同,因此要先确认商户账户接入的是 Sage Pay Direct、Server,还是较新的 Opayo 接口。
工作原理
后续扣款需要关联一笔成功的原始交易。常用字段包括:
TxType=REPEATVendorVendorTxCodeAmountCurrencyDescriptionRelatedVPSTxIdRelatedVendorTxCodeRelatedSecurityKey
各字段的含义如下:
VendorTxCode是本次扣款的新交易编号,每笔交易必须唯一。RelatedVPSTxId是初始交易返回的VPSTxId。RelatedVendorTxCode是初始交易使用的VendorTxCode。RelatedSecurityKey是初始交易返回的SecurityKey。
所以,首次付款成功后不能只保存订单号,至少还要安全保存后续交易需要使用的关联字段。
PHP 请求示例
下面是传统 Sage Pay 协议的请求结构。$endpoint 需要按照实际接入产品、测试环境和协议版本填写,不能直接将示例地址用于生产环境。
<?php
$endpoint = getenv('SAGEPAY_REPEAT_ENDPOINT');
$data = [
'VPSProtocol' => '3.00',
'TxType' => 'REPEAT',
'Vendor' => 'your_vendor_name',
'VendorTxCode' => 'repeat_' . bin2hex(random_bytes(12)),
'Amount' => '19.99',
'Currency' => 'GBP',
'Description' => 'Monthly subscription',
'RelatedVPSTxId' => '{ORIGINAL_VPSTXID}',
'RelatedVendorTxCode' => 'original_transaction_code',
'RelatedSecurityKey' => '{ORIGINAL_SECURITY_KEY}',
];
$ch = curl_init($endpoint);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data, '', '&'),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
],
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException('Sage Pay request failed: ' . curl_error($ch));
}
$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpStatus < 200 || $httpStatus >= 300) {
throw new RuntimeException(
'Sage Pay returned HTTP status ' . $httpStatus
);
}
/*
* 传统 Sage Pay 接口通常返回多行 key=value 内容,
* 但应以当前协议文档规定的格式为准。
*/
$result = [];
foreach (preg_split('/\r\n|\r|\n/', trim($response)) as $line) {
if ($line === '' || !str_contains($line, '=')) {
continue;
}
[$key, $value] = explode('=', $line, 2);
$result[trim($key)] = trim($value);
}
$status = $result['Status'] ?? null;
if ($status !== 'OK') {
$detail = $result['StatusDetail'] ?? 'Unknown gateway error';
throw new RuntimeException("Repeat payment failed: {$detail}");
}
echo 'Repeat payment accepted';
如果 PHP 版本低于 8.0,可以将:
str_contains($line, '=')
替换为:
strpos($line, '=') !== false
集成步骤
- 在商户后台确认账户是否支持 repeat payment 或连续扣款。
- 确认当前使用的 Sage Pay/Opayo 产品及协议版本。
- 查阅对应版本的官方协议文档,确认交易注册地址和必填字段。
- 在测试环境中完成一笔初始付款。
- 保存返回的
VPSTxId、VendorTxCode和SecurityKey。 - 创建新的唯一
VendorTxCode,提交TxType=REPEAT请求。 - 检查响应中的
Status和StatusDetail,不能只根据 HTTP 状态判断付款是否成功。 - 测试成功、失败、超时及重复提交等情况,确认无误后再切换到生产环境。
常见问题
为什么找不到 repeat payment 的源代码?
因为它通常是支付协议中的一种交易类型,并不是单独的软件包。PHP 端只需按照协议构造 HTTPS POST 请求。接入时主要需要处理字段、账户权限和交易状态。
可以只用订单号重复扣款吗?
通常不行。后续交易需要关联原始的支付网关交易,可能需要提交 RelatedVPSTxId、RelatedVendorTxCode 和 RelatedSecurityKey 等字段。
可以定时自动扣款吗?
网关只负责执行单次 REPEAT 请求,具体的扣款计划通常由你的系统管理。例如,可以使用队列或定时任务,在到期日生成新的唯一交易编号并调用接口。不要直接重试同一个请求,以免发生重复扣款。
能把银行卡号保存下来再提交吗?
不要自行保存完整卡号或 CVV。repeat payment 可以通过原交易引用完成后续扣款。保存和处理银行卡数据会显著扩大 PCI DSS 合规范围,而且 CVV 不应存储。
注意事项
- 测试环境和生产环境的交易标识不能混用。
- 金额应使用保留两位小数的十进制字符串,例如
19.99。 - 每次后续扣款都要使用唯一的
VendorTxCode。 - 发生网络超时时,不要立即重新扣款。应先查询交易状态,或按照官方建议处理。
- 记录请求编号、响应状态和错误详情,但不要将安全字段写入普通日志。
- repeat payment 并不是完整的订阅管理系统。账期、重试、退款和取消逻辑仍需由业务系统处理。
- 某些账户、卡种、收单配置或认证规则可能不支持后续扣款。实际能力应以商户合同、当前协议文档和 Opayo 支持团队的确认为准。
- 如果现有系统使用的是较新的 Opayo API,上述传统字段和请求格式可能不适用。此时应使用对应产品的 credential/token 或 recurring transaction 流程。
备注:内容仅供参考。
