文件 ERROR 3370 上的 Sage Pay / Opayo 凭证:RelatedVPSTxId 无法重复(PHP/cURL 解决方案)

发布于 2025-01-10 21:36:35 字数 9443 浏览 0 评论 0原文

问题

当我尝试重复类型为 AUTHORISE(但不是PAYMENT)的交易时,我从 Sage Pay 收到错误 3370。我正在使用 PHP/cURL 的服务器集成


解答

这很可能是因为您需要在初始 AUTHENTICATE 交易期间发送 CoF 值。这会将初始记录建立为有效的“存档凭证”,并允许您稍后执行重复交易。

简而言之,必须使用以下内容创建初始AUTHENTICATE记录:

COFUsage = FIRST
InitiatedType = CIT
MITType = UNSCHEDULED

这里是现在对我有用的完整 PHP/CURL 代码:


第 1 步:AUTHENTICATE

假设您正在使用服务器集成并且客户处于“会话中”,您的初始 cURL 代码将如下所示:

// Initialise cURL
$curl = curl_init();
// Set the Sage Pay server URL
$serverLive="https://live.sagepay.com/gateway/service/authorise.vsp"; 
// Connect to the Sage Pay server
curl_setopt($curl, CURLOPT_URL, $serverLive);
// Set cURL to post variables
curl_setopt($curl, CURLOPT_POST, 1);
// Declare account variables for posting to the Sage Pay server
$VPSProtocol="4.0"; // Must be 4.0 for CoF usage 
$Vendor="......."; // Your Sage Pay Vendor Name
// Declare product variables for posting to the Sage Pay server
$Amount=0.01; // This transaction will be for 1 pence
$Currency="GBP";
$Description="......."; // Product description
// Declare URL of your callback page for posting to the Sage Pay server
$NotificationURL="https://www.......";
// Create a unique 16-character VendorTxCode for posting to the Sage Pay server
$UserID=9999; // Unique user ID
$salt="d5s63ffd6s7fgdhs55377yrwesr24553"; // Encryption key
$VendorTxCode=substr(strtoupper(md5(date("U").$UserID.$salt)), 0, 16);
// Declare other variables to pass to Sage Pay (ie. customer name, email, billing address etc)
// These will have been entered via a form on your website
$CustomerName=".......";
$CustomerEmail=".......";
$BillingFirstnames=".......";
$BillingSurname=".......";
$BillingAddress1=".......";
$BillingCity=".......";
$BillingPostCode=".......";
$BillingCountry="GB";
$BillingPhone=".......";
$DeliveryFirstnames=".......";
$DeliverySurname=".......";
$DeliveryAddress1=".......";
$DeliveryCity=".......";
$DeliveryPostCode=".......";
$DeliveryCountry="GB";
$DeliveryPhone="......."; 

现在可能是将这些变量插入 MySQL 数据库的好时机。创建一个名为“sagepay”的表,其字段/值如下:

  • userID = $UserID
  • VendorTxCode = $VendorTxCode
  • TxType = AUTHENTICATE
  • Amount = $Amount
  • Description = $Description

您的 sagepay 数据库表中还应该有以下字段。这些将从空开始,稍后将进行 UPDATE(d):

  • 现在
  • 通过
  • cURL
  • 变量
  • 服务器
  • 状态
  • SecurityKey VPSTxId TxAuthNolatedVendorTxCodeRelatedSecurityKeyRelatedVPSTxIdRelatedTxAuthNoSchemeTraceID ACSTransID DSTransID
  • 发布

Sage Pay 您的 cURL 帖子应发送 $COFUsageFIRST,以与初始 AUTHENTICATE 交易和 $InitiatedType 相对应> 必须设置为 CIT 以指示客户正在“会话中”(即,他们稍后将在您的网站上输入付款详细信息):

// Post the variables to the Sage Pay server
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('Profile' => 'LOW', 'VPSProtocol' => $VPSProtocol, 'Vendor' => $Vendor, 'TxType' => 'AUTHENTICATE', 'VendorTxCode' => $VendorTxCode, **'Apply3DSecure' => '1', 'COFUsage' => 'FIRST', 'InitiatedType' => 'CIT',** 'Amount' => $Amount, 'Currency' => $Currency, 'Description' => $Description, 'CustomerName' => $CustomerName, 'CustomerEMail' => $CustomerEmail, 'BillingFirstnames' => $BillingFirstnames, 'BillingSurname' => $BillingSurname, 'BillingAddress1' => $BillingAddress1, 'BillingCity' => $BillingCity, 'BillingPostCode' => $BillingPostCode, 'BillingCountry' => $BillingCountry, 'BillingPhone' => $BillingPhone, 'DeliveryFirstnames' => $DeliveryFirstnames, 'DeliverySurname' => $DeliverySurname, 'DeliveryAddress1' => $DeliveryAddress1, 'DeliveryCity' => $DeliveryCity, 'DeliveryPostCode' => $DeliveryPostCode, 'DeliveryCountry' => $DeliveryCountry, 'DeliveryPhone' => $DeliveryPhone, 'NotificationURL' => $NotificationURL', 'Status' => 'OK'
)));
// This is supposed to speed things up (not sure if it does!)
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
// Request a response from cURL
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

以上代码将创建一个 验证记录在 Sage Pay 服务器上,并返回一个 cURL 字符串,其中包含您将用于更新之前创建的数据库记录的值。当您创建 AUTHORISE 交易时,这些变量将被重用(参见步骤 2):

// Get server response
$response = curl_exec($curl);
// Close cURL
curl_close ($curl);

$response string 转换为名为 $results[] 的数组:

// Convert $response string into an array called $results[]
$results = [];
foreach (explode("\n", $response) as $line) 
{
  list ($key, $value) = explode('=', $line, 2);
  $results[$key] = trim($value); // Trim to remove white space
}

包含以下变量在 $results[] 数组中。确保使用这些值更新您的初始AUTHENTICATE数据库记录。当您AUTHORISE交易并进行第一笔付款时,您需要调用它们:

$SecurityKey=$results['SecurityKey']; // Save this to your database
$VPSTxId=$results['VPSTxId']; // Save this to your database

$results[]还将包含以下变量:

$NextURL=$results['NextURL'];

一旦AUTHENTICATE 记录在 Sage Pay 服务器上创建,您可以使用 iFrame 向客户显示卡支付页面,源 URL 设置为 $NextURL

<iframe name="my_iframe" src="<?= $NextURL ?>" width='100%' height='520'></iframe>

此时,客户将输入他们的卡详细信息,如果一切顺利的话,交易将完成,iFrame 将更新您的 $NotificationURL

Sage Pay 会将以下变量传递到 $_REQUEST[] 数组中的 $NotificationURL。最好“修剪”这些值以确保不会出现空格:

$Status=trim($_REQUEST['Status']); // This should be "OK"
$TxAuthNo=trim($_REQUEST['TxAuthNo']);
$ACSTransID=trim($_REQUEST['ACSTransID']);
$DSTransID=trim($_REQUEST['DSTransID']);

使用这些值更新“sagepay”数据库表,然后显示“谢谢”消息。


第 2 步:授权

现在您在 Sage Pay 服务器上有一条AUTHENTICATE记录,并且在您的 MySQL 数据库表中也有一条相应的记录,您必须授权该交易才能进行初始付款。这涉及在 Sage Pay 服务器和 MySQL 数据库中创建新的 AUTHORISE 记录。

首先,为 AUTHORISE 记录创建一个新的 16 个字符的 $VendorTxCode

然后,选择原始 AUTHENTICATE 记录中的值并将其传输到“相关”变量中,以便重新提交到 Sage Pay:

// Declare "related" variables
$RelatedVendorTxCode = $VendorTxCode; // The original VendorTxCode you created
$RelatedVPSTxId = $VPSTxId; // The $VPSTxId returned in $results[] array  
$RelatedSecurityKey = $SecurityKey; // The $SecurityKey returned in $results[] array

现在是插入 $VendorTxCode 和这些“相关”变量的好时机 。相关的”变量作为 MySQL 数据库中的新记录。将此新记录的 TxType 字段设置为 AUTHORISE

接下来,通过 cURL 将变量传递给 Sage Pay,以在 Sage Pay 服务器上创建授权记录。请注意,$InitiatedType 现在为 MIT,表示客户不再“在会话中”,但 $COFUsage 值仍需要FIRST

// Create an AUTHORISE record
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('VPSProtocol' => $VPSProtocol, 'VendorTxCode' => $VendorTxCode, 'Vendor' => $Vendor, 'TxType' => 'AUTHORISE', **'Apply3DSecure' => '1', 'COFUsage' => 'FIRST', 'InitiatedType' => 'MIT', 'MITType' => 'UNSCHEDULED',** 'Amount' => $Amount, 'Description' => $Description, 'RelatedVPSTxId' => $RelatedVPSTxId, 'RelatedVendorTxCode' => $RelatedVendorTxCode, 'RelatedSecurityKey' => $RelatedSecurityKey, 'RelatedTxAuthNo' => $RelatedTxAuthNo)));

Sage Pay 将再次使用字符串进行响应 ($response)。像以前一样将 $response 转换为 $results[] 数组。这些是您最终将得到的一些变量:

$TxAuthNo
$VPSTxId
$SecurityKey
$SchemeTraceID
$ACSTransID
$DSTransID
$Status

使用这些变量更新 MySQL 数据库表中的 AUTHORISE 记录。当您重复交易时,您将需要这些变量。

$TxAuthNo 是一个授权代码,仅当在 Sage Pay 服务器上成功创建 AUTHORISE 记录时才会返回(即,如果 $Status 为“好的”)。

$SchemeTraceID 是您的 CoF“令牌”,用于重复成功的AUTHORISE交易。


第 3 步:重复

您可以使用以下 cURL 代码对授权交易进行重复。请注意,$COFUsage 值现在从 FIRST 更改为 SUBSEQUENT,并且您必须发送 $SchemeTraceID(令牌)验证交易是否为有效的“存档凭证”。 “相关”变量是原始 AUTHORISE 记录的变量(即 $VendorTxCode、$TxAuthNo、$VPSTxId 和 $SecurityKey):

curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('VPSProtocol' => $VPSProtocol, 'Vendor' => $Vendor, 'TxType' => 'REPEAT', 'VendorTxCode' => $VendorTxCode, **'Apply3DSecure' => '1', 'COFUsage' => 'SUBSEQUENT', 'InitiatedType' => 'MIT', 'MITType' => 'UNSCHEDULED', 'SchemeTraceID'=> $SchemeTraceID,** 'Amount' => $Amount, 'Currency' => $Currency, 'Description' => $Description, 'RelatedVPSTxId' => $RelatedVPSTxId, 'RelatedVendorTxCode' => $RelatedVendorTxCode, 'RelatedSecurityKey' => $RelatedSecurityKey, 'RelatedTxAuthNo' => $RelatedTxAuthNo )));

QUESTION

I get an ERROR 3370 from Sage Pay when trying to repeat transactions of type AUTHORISE (but not PAYMENT). I am using Server Integration with PHP/cURL.


ANSWER

This is most likely because you need to send CoF values during your initial AUTHENTICATE transaction. This establishes the initial record as a valid "Credentital on File" and allows you to carry out REPEAT transactions later.

In a nutshell, the initial AUTHENTICATE record must be created with:

COFUsage = FIRST
InitiatedType = CIT
MITType = UNSCHEDULED

HERE IS THE FULL PHP/CURL CODE THAT IS NOW WORKING FOR ME:


STEP 1: AUTHENTICATE

Assuming you are using Server Integration and the customer is "in session" your initial cURL code will look something like this:

// Initialise cURL
$curl = curl_init();
// Set the Sage Pay server URL
$serverLive="https://live.sagepay.com/gateway/service/authorise.vsp"; 
// Connect to the Sage Pay server
curl_setopt($curl, CURLOPT_URL, $serverLive);
// Set cURL to post variables
curl_setopt($curl, CURLOPT_POST, 1);
// Declare account variables for posting to the Sage Pay server
$VPSProtocol="4.0"; // Must be 4.0 for CoF usage 
$Vendor="......."; // Your Sage Pay Vendor Name
// Declare product variables for posting to the Sage Pay server
$Amount=0.01; // This transaction will be for 1 pence
$Currency="GBP";
$Description="......."; // Product description
// Declare URL of your callback page for posting to the Sage Pay server
$NotificationURL="https://www.......";
// Create a unique 16-character VendorTxCode for posting to the Sage Pay server
$UserID=9999; // Unique user ID
$salt="d5s63ffd6s7fgdhs55377yrwesr24553"; // Encryption key
$VendorTxCode=substr(strtoupper(md5(date("U").$UserID.$salt)), 0, 16);
// Declare other variables to pass to Sage Pay (ie. customer name, email, billing address etc)
// These will have been entered via a form on your website
$CustomerName=".......";
$CustomerEmail=".......";
$BillingFirstnames=".......";
$BillingSurname=".......";
$BillingAddress1=".......";
$BillingCity=".......";
$BillingPostCode=".......";
$BillingCountry="GB";
$BillingPhone=".......";
$DeliveryFirstnames=".......";
$DeliverySurname=".......";
$DeliveryAddress1=".......";
$DeliveryCity=".......";
$DeliveryPostCode=".......";
$DeliveryCountry="GB";
$DeliveryPhone="......."; 

Now is probably a good time to INSERT these variables into your MySQL database. Create a table called "sagepay" with field/values as follows:

  • userID = $UserID
  • VendorTxCode = $VendorTxCode
  • TxType = AUTHENTICATE
  • Amount = $Amount
  • Description = $Description

You should also have the following fields in your sagepay database table. These will start off empty and will be UPDATE(d) later:

  • SecurityKey
  • VPSTxId
  • TxAuthNo
  • RelatedVendorTxCode
  • RelatedSecurityKey
  • RelatedVPSTxId
  • RelatedTxAuthNo
  • SchemeTraceID
  • ACSTransID
  • DSTransID
  • Status

Now post your variables to the Sage Pay server via cURL. Your cURL post should send a $COFUsage value of FIRST to correspond with this being an initial AUTHENTICATE transaction and $InitiatedType must be set to CIT to indicate the customer is "in session" (ie. they are going to enter their payment details on your website in a moment):

// Post the variables to the Sage Pay server
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('Profile' => 'LOW', 'VPSProtocol' => $VPSProtocol, 'Vendor' => $Vendor, 'TxType' => 'AUTHENTICATE', 'VendorTxCode' => $VendorTxCode, **'Apply3DSecure' => '1', 'COFUsage' => 'FIRST', 'InitiatedType' => 'CIT',** 'Amount' => $Amount, 'Currency' => $Currency, 'Description' => $Description, 'CustomerName' => $CustomerName, 'CustomerEMail' => $CustomerEmail, 'BillingFirstnames' => $BillingFirstnames, 'BillingSurname' => $BillingSurname, 'BillingAddress1' => $BillingAddress1, 'BillingCity' => $BillingCity, 'BillingPostCode' => $BillingPostCode, 'BillingCountry' => $BillingCountry, 'BillingPhone' => $BillingPhone, 'DeliveryFirstnames' => $DeliveryFirstnames, 'DeliverySurname' => $DeliverySurname, 'DeliveryAddress1' => $DeliveryAddress1, 'DeliveryCity' => $DeliveryCity, 'DeliveryPostCode' => $DeliveryPostCode, 'DeliveryCountry' => $DeliveryCountry, 'DeliveryPhone' => $DeliveryPhone, 'NotificationURL' => $NotificationURL', 'Status' => 'OK'
)));
// This is supposed to speed things up (not sure if it does!)
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
// Request a response from cURL
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

The above code will create an AUTHENTICATE record on the Sage Pay server and return a cURL string containing values that you will use to UPDATE your previously created database record. These variables will be reused when you create the AUTHORISE transaction (see Step 2):

// Get server response
$response = curl_exec($curl);
// Close cURL
curl_close ($curl);

Convert the $response string into an array called $results[]:

// Convert $response string into an array called $results[]
$results = [];
foreach (explode("\n", $response) as $line) 
{
  list ($key, $value) = explode('=', $line, 2);
  $results[$key] = trim($value); // Trim to remove white space
}

The following variables are contained in the $results[] array. Make sure you UPDATE your initial AUTHENTICATE database record with these values. You will need to recall them when you come to AUTHORISE the transaction and take the first payment:

$SecurityKey=$results['SecurityKey']; // Save this to your database
$VPSTxId=$results['VPSTxId']; // Save this to your database

$results[] will also contain the following variable:

$NextURL=$results['NextURL'];

Once an AUTHENTICATE record is created on the Sage Pay server, you can display a card payment page to your customer using an iFrame with the source URL set to $NextURL

<iframe name="my_iframe" src="<?= $NextURL ?>" width='100%' height='520'></iframe>

At this point the customer will enter their card details and, if everything is in order, the transaction will be completed and the iFrame will update with your $NotificationURL

Sage Pay will pass the following variables to your $NotificationURL in the $_REQUEST[] array. It is a good idea to "trim" these values to ensure no white space creeps in:

$Status=trim($_REQUEST['Status']); // This should be "OK"
$TxAuthNo=trim($_REQUEST['TxAuthNo']);
$ACSTransID=trim($_REQUEST['ACSTransID']);
$DSTransID=trim($_REQUEST['DSTransID']);

UPDATE your "sagepay" database table with these values and then display your "Thank You" message.


STEP 2: AUTHORISE

Now you have an AUTHENTICATE record on the Sage Pay server, and a corresponding record in your MySQL database table, you must AUTHORISE the transaction to take the initial payment. This involves creating a new AUTHORISE record on the Sage Pay server and in your MySQL database.

First, create a new 16-character $VendorTxCode for the AUTHORISE record.

Then, SELECT and transfer the values from the original AUTHENTICATE record into "related" variables for resubmission to Sage Pay:

// Declare "related" variables
$RelatedVendorTxCode = $VendorTxCode; // The original VendorTxCode you created
$RelatedVPSTxId = $VPSTxId; // The $VPSTxId returned in $results[] array  
$RelatedSecurityKey = $SecurityKey; // The $SecurityKey returned in $results[] array

Now is a good time to INSERT the $VendorTxCode and these "related" variables as a new record in your MySQL database. Set the TxType field for this new record to AUTHORISE.

Next, pass your variables to Sage Pay via cURL to create an AUTHORISE record on the Sage Pay server. Note, the $InitiatedType is now MIT to indicate the customer is no longer "in session", but the $COFUsage value still needs to be FIRST:

// Create an AUTHORISE record
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('VPSProtocol' => $VPSProtocol, 'VendorTxCode' => $VendorTxCode, 'Vendor' => $Vendor, 'TxType' => 'AUTHORISE', **'Apply3DSecure' => '1', 'COFUsage' => 'FIRST', 'InitiatedType' => 'MIT', 'MITType' => 'UNSCHEDULED',** 'Amount' => $Amount, 'Description' => $Description, 'RelatedVPSTxId' => $RelatedVPSTxId, 'RelatedVendorTxCode' => $RelatedVendorTxCode, 'RelatedSecurityKey' => $RelatedSecurityKey, 'RelatedTxAuthNo' => $RelatedTxAuthNo)));

Sage Pay will respond again with a string ($response). Convert $response into a $results[] array as before. These are some of the variables you will end up with:

$TxAuthNo
$VPSTxId
$SecurityKey
$SchemeTraceID
$ACSTransID
$DSTransID
$Status

UPDATE the AUTHORISE record in your MySQL database table with these variables. You will need these variables for when you come to REPEAT the transaction.

$TxAuthNo is an authorisation code which is only returned if the AUTHORISE record is successfully created on the Sage Pay server (ie. if $Status is "OK").

$SchemeTraceID is your CoF "token" for repeating successful AUTHORISE transactions.


STEP 3: REPEAT

You can REPEAT against AUTHORISE transactions using the following cURL code. Note, the $COFUsage value now changes from FIRST to SUBSEQUENT and you must send the $SchemeTraceID (token) to verify the transaction as a valid "Credential on File". The "related" variables are those of the original AUTHORISE record (ie. $VendorTxCode, $TxAuthNo, $VPSTxId, and $SecurityKey):

curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('VPSProtocol' => $VPSProtocol, 'Vendor' => $Vendor, 'TxType' => 'REPEAT', 'VendorTxCode' => $VendorTxCode, **'Apply3DSecure' => '1', 'COFUsage' => 'SUBSEQUENT', 'InitiatedType' => 'MIT', 'MITType' => 'UNSCHEDULED', 'SchemeTraceID'=> $SchemeTraceID,** 'Amount' => $Amount, 'Currency' => $Currency, 'Description' => $Description, 'RelatedVPSTxId' => $RelatedVPSTxId, 'RelatedVendorTxCode' => $RelatedVendorTxCode, 'RelatedSecurityKey' => $RelatedSecurityKey, 'RelatedTxAuthNo' => $RelatedTxAuthNo )));

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烙印 2025-01-17 21:36:35

我也面临着同样的问题。但我已经使用了这个库,这个问题背后的原因是在第一个交易请求中,他们(Sagepay 服务器)得到空白 COFUsage、InitiatedType、MITType 参数
https://github.com/thephpleague/omnipay-sagepay

我安装了 4.0 版本的omnipay- sagepay 库而不是 3.0

{
"require": {
    "omnipay/sagepay": "~4.0"
}
}

,在第一笔交易中,我传递了这些额外的参数。

 $gateway->setCOFUsage("FIRST");
 $gateway->setInitiatedType("CIT");
 $gateway->setMITType("UNSCHEDULED");

对于重复交易,我已经传递了这些参数

$gateway->setCOFUsage('SUBSEQUENT');
$gateway->setInitiatedType('MIT');
$gateway->setMITType('UNSCHEDULED');
$gateway->setSchemeTraceID($TransactionReference['scheme_trace_Id']);

,并且它对我来说工作得很好。 sagepay 团队的回复

I was also facing same issue. But I have used this library and reason behind this issue is in the first transaction request they(Sagepay server) are getting blank COFUsage, InitiatedType, MITType params
https://github.com/thephpleague/omnipay-sagepay

I installed 4.0 version of omnipay-sagepay library rather then 3.0

{
"require": {
    "omnipay/sagepay": "~4.0"
}
}

and in the first transaction, I have passed these extra parameters.

 $gateway->setCOFUsage("FIRST");
 $gateway->setInitiatedType("CIT");
 $gateway->setMITType("UNSCHEDULED");

And for repeat transactions, I have passed these params

$gateway->setCOFUsage('SUBSEQUENT');
$gateway->setInitiatedType('MIT');
$gateway->setMITType('UNSCHEDULED');
$gateway->setSchemeTraceID($TransactionReference['scheme_trace_Id']);

and it's working fine for me. Response from sagepay team

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文