0

Swish is a Swedish payment provider. You pay by simply sending money to a phone number.

This is a API for the new PAYOUT-service offered by Swish. Not the same as PAYMENT service, so dont confuse yourself with that.

There is no PHP examples available on their website and I cannot manage to get a 200 response.

If you pro's can help me solve this I think this many others can benefit from the solution in the future.

So here is my current code.

$payload = [
  "payoutInstructionUUID" => "E4D773858AF5459B96ABCA4B9DBFF94D",
  "payerPaymentReference" => "payerRef",
  "payerAlias" => "1231388446",
  "payeeAlias" => "46712345678",
  "payeeSSN" => "198602111638",
  "amount" => "100.00",
  "currency" => "SEK",
  "payoutType" => "PAYOUT",
  "message" => "Message to the recipient.",
  "instructionDate" => carbon::now(),
  "signingCertificateSerialNumber" => "667A2C6E068B76988AB657351F5AF636"
];

$pkey =     openssl_pkey_get_private(file_get_contents('Swish_Merchant_TestSigningCertificate_1234679304.key'), 'swish');
$payloadHash =  hash('sha512', json_encode($payload));


$signature =   openssl_sign($payloadHash, $signature, $pkey) ? base64_encode($signature) : 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, 0);
curl_setopt($ch, CURLOPT_SSLVERSION, 6);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);


curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));
$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);

curl_close($ch);

It gives me this response

*   Trying 213.132.115.90:443...
* Connected to mss.cpc.getswish.net (213.132.115.90) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: Swish_TLS_RootCA.pem
*  CApath: none
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=SE; ST=Stockholms l�n; L=Stockholm; O=GetSwish AB; OU=IT; CN=mss.cpc.getswish.net
*  start date: Feb 18 00:00:00 2020 GMT
*  expire date: May 19 12:00:00 2022 GMT
*  subjectAltName: host "mss.cpc.getswish.net" matched cert's "mss.cpc.getswish.net"
*  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=GeoTrust RSA CA 2018
*  SSL certificate verify ok.
> POST /swish-cpcapi/api/v1/payouts HTTP/1.1
Host: mss.cpc.getswish.net
Accept: */*
Content-Type:application/json
Content-Length: 1172

* Mark bundle as not supporting multiuse
< HTTP/1.1 400 
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Thu, 21 Oct 2021 19:52:53 GMT
< Connection: close
< 
* Closing connection 0
[
   {
      "errorCode":"PA01",
      "errorMessage":"Parameter is not correct.",
      "additionalInformation":null
   }
]

As you see the response does not very accurate tell me whats wrong. I tried change the signature to some nonce and I still got the same error message. This makes me believe that the signature is incorrect.

There is no registration required for the test environment. You can test this on you own computer.

Here is a link to the documentation https://developer.swish.nu/documentation/getting-started/swish-payout-api

Certificates are found here (under Managing Certificates) https://developer.swish.nu/documentation/environments

Phanteon
  • 1
  • 1
  • Error code `PA01`. `The Swish number is not a Swish Handel (Swish Företag does not work) | BjornTech is not selected as Technical supplier. | The number is new and not activated from the Bank-side. | The number is entered wrongly, please double check that you have entered it ` (found here https://wordpress.org/support/topic/swish-error-message-pa01/) – cottton Oct 21 '21 at 20:41
  • Were you able to find a solution? I tried Hampus's mod below, but I get the same odious non-descript PA01 "Something is wrong but I won't tell you what" message. The certificate files have been updated by Swish, but not errorrs from openssl_* in PHP.. – Torbjörn Stabo May 20 '22 at 16:43
  • Yes, I paid a professional to fix it for me. I will ask if If I have right to publish his solution here. And save you some pain ;-) – Phanteon May 22 '22 at 08:49
  • @Phanteon Please feel free to do so, I'd really appreciate it. Otherwise my next step would - have to - be something like compiling the Java example in the docs and compare it with the PHP request using Wireshark, or something :-p – Torbjörn Stabo May 23 '22 at 10:29
  • I posted a link in a new answer but it got deleted by a moderator (i dont know why). But here you have it again https://gist.github.com/KFoobar/044fd10becba6b54460dc937fb855e0f – Phanteon May 27 '22 at 11:00

1 Answers1

2

Try to change

$signature =   openssl_sign($payloadHash, $signature, $pkey) ? base64_encode($signature) : null;

to

$signature =   openssl_sign($payloadHash, $signature, $pkey, OPENSSL_ALGO_SHA512) ? base64_encode($signature) : null;