Payment verification
As soon as payment or refund succeeds or fails, kevin. sends you a webhook. Webhooks are just HTTP POST requests to your web server. Your
Webhook-URL
must return a response with a 200 HTTP status code. Any other HTTP response code will be considered as a failure. It is not required for your webhook response to return any content. We will retry failed webhooks periodically for up to two days until we receive a response with 200 HTTP status code.Webhook is just a signal about the final payment status, which cannot be changed. If you need any additional information about the payment, you have to fetch it independently using the
getPayment
endpoint or attach your own query parameters to your Webhook-URL
. Below you can find the example of a webhook request:Bank Payment
Card Payment
Refund
{
"id": "e4dd60bb-574f-4a13-910a-57c9795d905f",
"bankStatus": "ACSC",
"statusGroup": "completed",
"type": "PAYMENT"
}
{
"id": "e4dd60bb-574f-4a13-910a-57c9795d905f",
"cardStatus": "payment_success",
"statusGroup": "completed",
"type": "PAYMENT"
}
{
"id": "1",
"paymentId": "e4dd60bb-574f-4a13-910a-57c9795d905f",
"statusGroup": "completed",
"type": "PAYMENT_REFUND"
}
It’s strongly advised to use a raw request body for the hash computing process.
Webhooks do not confirm that money is received. If bank supports instant payments, funds are received in a couple of minutes. Otherwise, the transaction will be settled within 1-3 work days.
In order to meet all security requirements, kevin. signs every webhook request. The request contains two headers:
X-Kevin-Timestamp
- the timestamp in milliseconds when the request was sent by kevin.X-Kevin-Signature
- the signature which is computed using theHMAC-SHA256
algorithm.
You can validate the signature by combining the uppercase HTTP method of the request, the request URL, timestamp and the request body into one single string and then generating it using the
HMAC-SHA256
algorithm with your endpointSecret
.ATTENTION:
Client Secret
is different key. If you do not have yourEndpoint Secret,
please email [email protected].We recommend rejecting the webhook request if the signature is older than 5 minutes.
Below you can find the signature generation code for webhook request confirmation:
PHP
Node.js
Pseudocode
1
use Kevin\SecurityManager;
2
3
$endpointSecret = 'your-endpoint-secret';
4
$webhookUrl = 'your-webhook-url';
5
6
// Timestamp is provided in milliseconds
7
$timestampTimeout = 300000;
8
9
$requestBody = file_get_contents('php://input');
10
$headers = getallheaders();
11
12
$isValid = SecurityManager::verifySignature(
13
$endpointSecret,
14
$requestBody,
15
$headers,
16
$webhookUrl,
17
$timestampTimeout
18
);
19
20
http_response_code(200);
Make sure that received webhook is authentic. The example below is written using kevin. Node.js library.
1
const kevin = require('@kevin.eu/kevin-platform-client');
2
3
const endpointSecret = 'my-endpoint-secret';
4
5
const securityManager = new kevin.SecurityManager(endpointSecret);
6
7
// webhook request headers object
8
const headers = req.headers;
9
10
// webhook request body object
11
const body = req.body;
12
13
// URL to which webhook was requested
14
const webhookUrl = 'https://example.com/notify?orderId=123';
15
16
// Timestamp timeout in milliseconds
17
const timestampTimeout = '300000';
18
19
const isWebhookSignatureValid = securityManager.verifySignature(body, headers, webhookUrl, timestampTimeout);
httpMethod = 'POST'
requestUrl = 'https://yourapp.com/notify'
timestamp = '1600000000000'
endpointSecret = 'SECRET'
// Bank payment payload:
requestBody = '{"id":"e4dd60bb-574f-4a13-910a-57c9795d905f","bankStatus":"ACSC","statusGroup":"completed","type":"PAYMENT"}'
expectedSignature = 0a3ac91865c78ac9b675129f24ee3f25a71b02d1e83976833f0f139db6508777
// Card payment payload:
requestBody = '{"id":"e4dd60bb-574f-4a13-910a-57c9795d905f","cardStatus":"paid","statusGroup":"completed","type":"PAYMENT"}'
expectedSignature = 54cf5691f8d121f3b79bc1d102709975ff2ad39143e189043841c9c55fbe0902
// Hybrid payment payload:
requestBody = '{"id":"e4dd60bb-574f-4a13-910a-57c9795d905f","hybridStatus":"created","statusGroup":"completed","type":"PAYMENT"}'
expectedSignature = 4492b9761e7897b7f532706ea7bf87c1f9f7d6f1513d10c1c76ee0e41b9986ee
data = httpMethod + requestUrl + timestamp + requestBody
signature = HMAC_SHA256(data, endpointSecret)
Last modified 3mo ago