BLIK OneClick
BLIK OneClick enables one-click payments without requiring the customer to enter a six-digit BLIK code for subsequent transactions. The customer registers a bank alias during the first payment and then pays with one click.
Benefits
- Faster payments: no T6 code for subsequent transactions
- Higher conversion: fewer steps in the payment process
- Customer convenience: one-click payment
How BLIK OneClick works
The process has two stages:
- Alias registration: the first payment uses a BLIK code and includes consent to save the alias
- Alias payment: subsequent payments do not require a BLIK code
/api/v1_0/payments/registerComplete registration contract: parameters, checksum, and error codes.Full contract in the API Reference
Requirements
- An active Payment Point with BLIK OneClick enabled
- Secure server-side storage for
alias_value, associated with the customer's account - Access to the customer's IP address and User-Agent, as required by applicable regulations
Endpoint
POST https://api-payments.dpay.pl/api/v1_0/payments/register
Content-Type: application/json
Register an alias (first payment)
For the first payment, the customer enters a BLIK code and consents to saving the alias. The request is the same as for BLIK Level 0, with the additional register_blik_alias field.
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
transactionType | string | Yes | "transfers" |
service | string | Yes | Service name from the panel |
value | string | Yes | Amount in PLN |
url_success | string | Yes | URL used after a successful payment |
url_fail | string | Yes | URL used after a failed payment |
url_ipn | string | Yes | URL for IPN notifications |
checksum | string | Yes | SHA-256 checksum |
blik_code | string | Yes | Six-digit BLIK code |
user_ip | string | Yes | Customer's IP address |
user_agent | string | Yes | Customer's User-Agent header |
register_blik_alias | object | Yes | Alias data to register |
alias_ipn_url | string | No | URL for alias-status notifications, maximum 500 characters; if omitted, notifications are sent to url_ipn |
register_blik_alias object
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Alias label visible to the customer, maximum 50 characters |
type | string | Yes | Alias type; it must be "UID" |
value | string | No | Your own alias value, maximum 128 characters; if omitted, dpay generates one automatically |
Checksum generation
Generate the checksum exactly as for a standard payment:
sha256({service}|{SecretHash}|{value}|{url_success}|{url_fail}|{url_ipn})
We recommend providing your own value in register_blik_alias.value, such as an identifier generated by your system, and storing it on your server in association with the customer's account. You need it for subsequent alias payments and to check the alias status with POST /blik/aliases. If you omit the field, dpay generates the value automatically.
Example request
cURL
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "transfers",
"service": "abc123",
"value": "29.99",
"url_success": "https://myshop.example/success",
"url_fail": "https://myshop.example/error",
"url_ipn": "https://myshop.example/api/ipn",
"checksum": "e3b0c44298fc1c149afb...",
"blik_code": "123456",
"user_ip": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"register_blik_alias": {
"label": "My shop",
"type": "UID"
}
}'
PHP
<?php
$service = getenv('DPAY_SERVICE');
$secretHash = getenv('DPAY_SECRET_HASH');
$value = '29.99';
$urlSuccess = 'https://myshop.example/success';
$urlFail = 'https://myshop.example/error';
$urlIpn = 'https://myshop.example/api/ipn';
$checksum = hash('sha256',
$service . '|' . $secretHash . '|' . $value . '|' .
$urlSuccess . '|' . $urlFail . '|' . $urlIpn
);
$payload = json_encode([
'transactionType' => 'transfers',
'service' => $service,
'value' => $value,
'url_success' => $urlSuccess,
'url_fail' => $urlFail,
'url_ipn' => $urlIpn,
'checksum' => $checksum,
'blik_code' => $_POST['blik_code'],
'user_ip' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'register_blik_alias' => [
'label' => 'My shop',
'type' => 'UID',
],
]);
$ch = curl_init('https://api-payments.dpay.pl/api/v1_0/payments/register');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
JavaScript (Node.js / Express)
const crypto = require('crypto');
const axios = require('axios');
async function registerBlikAlias(req, res) {
const service = process.env.DPAY_SERVICE;
const secretHash = process.env.DPAY_SECRET_HASH;
const value = '29.99';
const urlSuccess = 'https://myshop.example/success';
const urlFail = 'https://myshop.example/error';
const urlIpn = 'https://myshop.example/api/ipn';
const checksum = crypto
.createHash('sha256')
.update(`${service}|${secretHash}|${value}|${urlSuccess}|${urlFail}|${urlIpn}`)
.digest('hex');
const response = await axios.post(
'https://api-payments.dpay.pl/api/v1_0/payments/register',
{
transactionType: 'transfers',
service,
value,
url_success: urlSuccess,
url_fail: urlFail,
url_ipn: urlIpn,
checksum,
blik_code: req.body.blik_code,
user_ip: req.ip,
user_agent: req.headers['user-agent'],
register_blik_alias: {
label: 'My shop',
type: 'UID',
},
}
);
return response.data;
}
API response
{
"error": false,
"msg": "Internal processing",
"status": true,
"transactionId": "abc-def-123-456"
}
The status field is a Boolean (true or false).
After this response, the customer must approve both the transaction and the alias registration in their banking app. You receive the payment result through IPN.
Pay with an alias (OneClick)
For subsequent payments, the customer does not need to enter a BLIK code. Send the saved alias_value instead.
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
transactionType | string | Yes | "transfers" |
service | string | Yes | Service name from the panel |
value | string | Yes | Amount in PLN |
url_success | string | Yes | URL used after a successful payment |
url_fail | string | Yes | URL used after a failed payment |
url_ipn | string | Yes | URL for IPN notifications |
checksum | string | Yes | SHA-256 checksum |
blik_alias | string | Yes | BLIK OneClick alias, maximum 128 characters |
user_ip | string | Yes | Customer's IP address |
user_agent | string | Yes | Customer's User-Agent header |
Do not send blik_code or register_blik_alias when paying with an alias; blik_alias is mutually exclusive with both. The blik_code and register_blik_alias pair is valid and required when registering an alias during the first payment.
Example request
cURL
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "transfers",
"service": "abc123",
"value": "29.99",
"url_success": "https://myshop.example/success",
"url_fail": "https://myshop.example/error",
"url_ipn": "https://myshop.example/api/ipn",
"checksum": "e3b0c44298fc1c149afb...",
"blik_alias": "a1b2c3d4e5f6...",
"user_ip": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}'
PHP
<?php
$service = getenv('DPAY_SERVICE');
$secretHash = getenv('DPAY_SECRET_HASH');
$value = '29.99';
$urlSuccess = 'https://myshop.example/success';
$urlFail = 'https://myshop.example/error';
$urlIpn = 'https://myshop.example/api/ipn';
$checksum = hash('sha256',
$service . '|' . $secretHash . '|' . $value . '|' .
$urlSuccess . '|' . $urlFail . '|' . $urlIpn
);
// $aliasValue - the customer's previously saved alias
$payload = json_encode([
'transactionType' => 'transfers',
'service' => $service,
'value' => $value,
'url_success' => $urlSuccess,
'url_fail' => $urlFail,
'url_ipn' => $urlIpn,
'checksum' => $checksum,
'blik_alias' => $aliasValue,
'user_ip' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
]);
$ch = curl_init('https://api-payments.dpay.pl/api/v1_0/payments/register');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
JavaScript (Node.js / Express)
const crypto = require('crypto');
const axios = require('axios');
async function payWithBlikAlias(req, res) {
const service = process.env.DPAY_SERVICE;
const secretHash = process.env.DPAY_SECRET_HASH;
const value = '29.99';
const urlSuccess = 'https://myshop.example/success';
const urlFail = 'https://myshop.example/error';
const urlIpn = 'https://myshop.example/api/ipn';
const checksum = crypto
.createHash('sha256')
.update(`${service}|${secretHash}|${value}|${urlSuccess}|${urlFail}|${urlIpn}`)
.digest('hex');
// aliasValue - the customer's previously saved alias
const aliasValue = await getUserBlikAlias(req.user.id);
const response = await axios.post(
'https://api-payments.dpay.pl/api/v1_0/payments/register',
{
transactionType: 'transfers',
service,
value,
url_success: urlSuccess,
url_fail: urlFail,
url_ipn: urlIpn,
checksum,
blik_alias: aliasValue,
user_ip: req.ip,
user_agent: req.headers['user-agent'],
}
);
return response.data;
}
API response
{
"error": false,
"msg": "Internal processing",
"status": true,
"transactionId": "abc-def-123-456"
}
The status field is a Boolean (true or false).
Depending on the bank's settings, the customer may be asked to approve the transaction in their banking app. You receive the payment result through IPN.
Manage aliases
Retrieve an alias
Check the BLIK alias registered for a customer.
POST/api/v1_0/payments/blik/aliasesComplete contract: parameters and alias-status fields.Full contract in the API Reference
Endpoint
POST https://api-payments.dpay.pl/api/v1_0/payments/blik/aliases
Content-Type: application/json
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name from the panel |
alias_value | string | Yes | Alias value |
alias_type | string | No | Alias type; defaults to "UID" |
checksum | string | Yes | SHA-256 checksum |
Checksum generation
sha256({service}|{secret}|{alias_value})
Example request
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/blik/aliases \
-H "Content-Type: application/json" \
-d '{
"service": "abc123",
"alias_value": "a1b2c3d4e5f6...",
"alias_type": "UID",
"checksum": "f5a3b2c1d0..."
}'
Response
The data field is a single object describing the alias:
{
"status": "success",
"data": {
"alias_value": "a1b2c3d4e5f6...",
"alias_type": "UID",
"status": "ACTIVE",
"expiration_date": "2027-03-22",
"apps": [
{ "key": "app1", "label": "Bank app" }
]
}
}
| Field | Type | Description |
|---|---|---|
alias_value | string|null | Alias value |
alias_type | string | Always "UID" |
status | string|null | Current alias status, such as "ACTIVE", "INACTIVE", "UNREGISTERED", or "EXPIRED" |
expiration_date | string|null | Alias expiration date |
apps | array | Banking apps associated with the alias, as { key, label } objects |
Unregister an alias
Remove a registered BLIK alias.
POST/api/v1_0/payments/blik/aliases/unregisterComplete BLIK alias unregistration contract.Full contract in the API Reference
Endpoint
POST https://api-payments.dpay.pl/api/v1_0/payments/blik/aliases/unregister
Content-Type: application/json
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name from the panel |
alias_value | string | Yes | Alias value to unregister |
alias_type | string | Yes | Alias type, "UID" |
reason | string | No | Reason for unregistering the alias |
checksum | string | Yes | SHA-256 checksum |
Checksum generation
sha256({service}|{secret}|{alias_value})
Example request
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/blik/aliases/unregister \
-H "Content-Type: application/json" \
-d '{
"service": "abc123",
"alias_value": "a1b2c3d4e5f6...",
"alias_type": "UID",
"reason": "The customer requested removal",
"checksum": "f5a3b2c1d0..."
}'
Response
{
"status": "success",
"data": {
"status": "success"
}
}
Alias notifications (IPN)
dpay.pl sends an alias_update IPN notification to the merchant endpoint whenever an alias status changes, including registration, unregistration, and expiration.
The notification is sent to the alias_ipn_url provided during transaction registration. If that field was omitted, dpay uses url_ipn.
Notification schema
dpay.pl sends a POST request with the Content-Type: application/json header and the following body:
{
"id": "abc-def-123-456",
"type": "alias_update",
"change_type": "ALIAS_REGISTER",
"alias_type": "UID",
"alias_status": "ACTIVE",
"alias_key": "a1b2c3d4e5f6...",
"alias_label": "Moja karta",
"alias_expire_at": "2027-01-01T00:00:00+00:00",
"change_reason_category": null,
"change_reason_message": null,
"version": 1,
"signature": "e3b0c44298fc..."
}
Field descriptions
| Field | Type | Description |
|---|---|---|
id | string | dpay.pl transaction identifier |
type | string | Notification type; always "alias_update" |
change_type | string|null | Change type: "ALIAS_REGISTER", "ALIAS_UPDATE", "ALIAS_UNREGISTER", "ALIAS_EXPIRED", "ALIAS_DECLINED", or "SCA_REJECTED" |
alias_type | string|null | Alias type, for example "UID" |
alias_status | string|null | Current alias status: "ACTIVE", "INACTIVE", "UNREGISTERED", "EXPIRED", "DECLINED", or "SCA_REJECTED" |
alias_key | string|null | Alias identifier; the same value used as alias_value for subsequent payments |
alias_label | string|null | Alias label; it can be empty if no label was assigned |
alias_expire_at | string|null | Alias expiration timestamp in ISO 8601 format; it can be empty |
change_reason_category | string|null | Change-reason category |
change_reason_message | string|null | Change-reason description |
version | integer | Schema version, currently 1 |
signature | string | Digital signature used to verify authenticity |
The alias_key field contains the alias identifier—the same alias_value used for payments—so you can correlate the notification with the stored alias. The id field identifies the initiating transaction. You can retrieve the current alias status and expiration date at any time with POST /blik/aliases.
Signature verification
The signature uses SHA-256:
sha256({id}{SecretHash}{type}{version})
Values are concatenated without a separator, exactly as in a standard IPN signature.
PHP
<?php
$data = json_decode(file_get_contents('php://input'), true);
if (!$data || $data['type'] !== 'alias_update') {
http_response_code(400);
exit;
}
$secretHash = 'TWOJ_SECRET_HASH';
$expectedSignature = hash('sha256',
$data['id'] . $secretHash . $data['type'] . $data['version']
);
if (!hash_equals($expectedSignature, $data['signature'])) {
http_response_code(403);
echo 'Invalid signature';
exit;
}
// The signature is valid; handle the alias change
// Correlate the alias by alias_key (= your alias_value) or by transaction $data['id']
switch ($data['change_type']) {
case 'ALIAS_REGISTER':
// Alias registered; mark the customer's alias as active
break;
case 'ALIAS_UPDATE':
// Alias data changed; refresh its status through POST /blik/aliases
break;
case 'ALIAS_UNREGISTER':
// Alias unregistered; remove it from the database
break;
case 'ALIAS_EXPIRED':
// Alias expired; mark it as inactive
break;
case 'ALIAS_DECLINED':
case 'SCA_REJECTED':
// Registration rejected by the customer or bank; remove the alias
break;
}
http_response_code(200);
echo 'OK';
Node.js
const crypto = require('crypto');
app.post('/api/alias-ipn', (req, res) => {
const data = req.body;
if (!data || data.type !== 'alias_update') {
return res.status(400).send('Invalid payload');
}
const secretHash = 'TWOJ_SECRET_HASH';
const expectedSignature = crypto
.createHash('sha256')
.update(`${data.id}${secretHash}${data.type}${data.version}`)
.digest('hex');
if (expectedSignature !== data.signature) {
return res.status(403).send('Invalid signature');
}
// The signature is valid; handle the alias change
// Correlate the alias by alias_key (= your alias_value) or by transaction data.id
switch (data.change_type) {
case 'ALIAS_REGISTER':
// Alias registered; mark the customer's alias as active
break;
case 'ALIAS_UPDATE':
// Alias data changed; refresh its status through POST /blik/aliases
break;
case 'ALIAS_UNREGISTER':
// Alias unregistered; remove it from the database
break;
case 'ALIAS_EXPIRED':
// Alias expired; mark it as inactive
break;
case 'ALIAS_DECLINED':
case 'SCA_REJECTED':
// Registration rejected by the customer or bank; remove the alias
break;
}
res.status(200).send('OK');
});
Retry schedule
The retry mechanism is the same as for standard IPN notifications:
| Attempt | Delay | Time since the first attempt |
|---|---|---|
| 1 | immediately | 0 min |
| 2 | 2 min | 2 min |
| 3 | 4 min | 6 min |
| 4 | 8 min | 14 min |
| 5 | 16 min | 30 min |
| 6 | 32 min | ~1 h |
| 7 | 64 min | ~2 h |
| 8 | 128 min | ~4 h |
| 9 | 256 min | ~8.5 h |
| 10 | 512 min | ~17 h |
Your endpoint must respond with HTTP 200 and the body "OK". Otherwise, dpay.pl retries delivery.
Your endpoint can receive multiple notifications about the same alias. Make the handler idempotent so processing the same notification more than once does not create errors or duplicates.
Validation and constraints
| Rule | Description |
|---|---|
| Mutually exclusive fields | blik_alias cannot be sent with blik_code or register_blik_alias. The blik_code and register_blik_alias pair is valid for alias registration |
register_blik_alias.label | Maximum 50 characters |
register_blik_alias.type | Must be "UID" |
register_blik_alias.value | Optional, maximum 128 characters |
alias_value | Maximum 128 characters |
blik_code | Exactly six digits |
Rate limits
| Endpoint | Limit |
|---|---|
POST /payments/register | 120 requests/min |
POST /blik/aliases | 60 requests/min |
POST /blik/aliases/unregister | 30 requests/min |
Error handling
When a payment is declined, the registration response has the form {"error": true, "msg": "Transaction canceled", "status": false, ...}. The error code is in additionalInfo.error, with an optional description in additionalInfo.error_description.
In test mode (sandbox), the following simulation codes are used:
| Error code | Description | Action |
|---|---|---|
DECLINE | Transaction declined | Ask the customer to retry |
EXPIRED_CARD | Payment instrument expired | Inform the customer |
INSUFFICIENT_FUNDS | Insufficient funds | Inform the customer |
USER_DECLINED | Customer declined the transaction in their banking app | Ask the customer to retry |
TIMEOUT | Timed out while waiting for confirmation | Ask for a new code |
ALIAS_NOT_FOUND | Alias not found | Register a new alias or use a BLIK code |
SYSTEM_ERROR | System error | Retry later |
In production, additionalInfo.error contains the raw BLIK decline code passed through without modification, or one of the following codes:
| Error code | Description | Action |
|---|---|---|
ALIAS_NOT_FOUND | Alias not found | Register a new alias or use a BLIK code |
ALIAS_APP_NOT_FOUND | The selected banking app is not associated with the alias | Retrieve the app list with POST /blik/aliases |
ALIAS_APP_AMBIGUOUS | The alias is associated with multiple apps and requires a selection | Let the customer select an app from the apps list |
INTERNAL_ERROR | Internal error | Retry later |
If an alias expires or the customer unregisters it in their banking app, register it again during the next payment made with a BLIK code.