PHP调用Swish Payout API返回PA01错误解决方案求助
问题排查及修复方案
核心问题点
- instructionDate字段格式错误:直接传入Carbon对象,未序列化为Swish要求的ISO 8601格式字符串
- 签名逻辑错误:
- 重复计算哈希:
openssl_sign本身支持直接指定摘要算法,不需要提前对payload做hash - 未指定签名算法:默认使用SHA1,不符合Swish要求的SHA512算法
- payload序列化不一致:签名用的payload序列化结果必须和最终请求体中payload的序列化结果完全一致,需要固定json_encode参数避免格式差异
- 重复计算哈希:
- 测试用payeeSSN不符合要求:瑞典SSN有固定格式要求,测试时可使用官方指定的测试值
修复后的代码
// 1. 修正payload字段格式 $payload = [ "payoutInstructionUUID" => "E4D773858AF5459B96ABCA4B9DBFF94D", "payerPaymentReference" => "payerRef", "payerAlias" => "1231388446", "payeeAlias" => "46712345678", "payeeSSN" => "191212121212", // 官方测试用合法瑞典SSN "amount" => "100.00", "currency" => "SEK", "payoutType" => "PAYOUT", "message" => "Message to the recipient.", // 修正为标准ISO 8601格式 "instructionDate" => Carbon::now()->toIso8601String(), "signingCertificateSerialNumber" => "667A2C6E068B76988AB657351F5AF636" ]; // 固定json_encode参数,保证签名和请求的payload序列化完全一致 $jsonPayload = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); $pkey = openssl_pkey_get_private(file_get_contents('Swish_Merchant_TestSigningCertificate_1234679304.key'), 'swish'); // 直接对原始payload json字符串签名,指定SHA512算法,不需要提前hash $signature = openssl_sign($jsonPayload, $signatureRaw, $pkey, OPENSSL_ALGO_SHA512) ? base64_encode($signatureRaw) : null; $request = [ "payload" => $payload, "callbackUrl" => "https://postb.in/1634560192746-3820346647407", "signature" => $signature ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/payouts'); curl_setopt($ch, CURLOPT_PORT, 443); curl_setopt($ch, CURLOPT_VERBOSE, true); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_SSLCERT, 'Swish_Merchant_TestCertificate_1234679304.p12'); curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'P12'); curl_setopt($ch, CURLOPT_SSLCERTPASSWD, 'swish'); curl_setopt($ch, CURLOPT_SSLKEY, 'Swish_Merchant_TestCertificate_1234679304.key'); curl_setopt($ch, CURLOPT_SSLKEYPASSWD, 'swish'); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); curl_setopt($ch, CURLOPT_CAINFO, 'Swish_TLS_RootCA.pem'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); // 生产环境必须开启校验 curl_setopt($ch, CURLOPT_SSLVERSION, 6); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); // 请求序列化时也用同样的json_encode参数保证一致性 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); $f = tmpfile(); curl_setopt($ch, CURLOPT_STDERR, $f); $results = curl_exec($ch); fseek($f, 0); echo "Verbose information:\n<pre>", fread($f, 32 * 1024), "</pre>\n"; fclose($f); $info = curl_errno($ch)>0 ? array("curl_error_".curl_errno($ch)=>curl_error($ch)) : curl_getinfo($ch); print_r($info); print_r($results); curl_close($ch);
补充校验点
如果修改后仍报错,可先打印$jsonPayload和最终请求体的payload部分,确认两边结构完全一致,另外检查signingCertificateSerialNumber是否和实际使用的签名证书序列号完全匹配。
内容的提问来源于stack exchange,提问作者Phanteon
相关产品推荐
相关产品推荐

