BLIK - płatności cykliczne (subskrypcje)
Płatności cykliczne BLIK pozwalają obciążać klienta bez jego udziału przy każdej płatności - idealne dla subskrypcji i abonamentów. Klient jednorazowo rejestruje alias typu PAYID (potwierdzając kodem BLIK w aplikacji bankowej), a kolejne obciążenia inicjujesz z serwera, przekazując zapisany alias.
Jak to działa?
Proces składa się z dwóch etapów:
- Rejestracja aliasu PAYID - transakcja z kwotą
0, kodem BLIK i obiektemregister_blik_recurring_alias. Klient potwierdza zgodę na płatności cykliczne w aplikacji bankowej. - Obciążenia cykliczne - kolejne płatności z
transactionType: "blik_recurring"i polemblik_alias, inicjowane przez Twój serwer bez udziału klienta.
Wymagania
- Aktywny Punkt Płatności z włączoną obsługą płatności cyklicznych BLIK oraz wybranym modelem odnowienia (skontaktuj się z BOK dpay)
- Możliwość przechowywania wartości aliasu po stronie serwera (powiązanej z kontem klienta)
- Dostęp do adresu IP i User-Agent klienta przy rejestracji (wymagane przez regulacje)
Modele odnowienia
Przy rejestracji aliasu wskazujesz model kontroli obciążeń:
| Model | Opis |
|---|---|
A | Kontrola po stronie banku klienta - limity i odnowienia zarządza aplikacja bankowa |
M | Kontrola po stronie sklepu - dpay waliduje każde obciążenie względem limitów podanych przy rejestracji (limit_amt, tot_limit_amt) |
O | Bez kontroli limitów |
Model musi być aktywny dla Twojego serwisu - użycie nieaktywnego modelu zwróci błąd rejestracji.
Endpoint
POST https://api-payments.dpay.pl/api/v1_0/payments/register
Content-Type: application/json
Krok 1: Rejestracja aliasu PAYID
Rejestracja to transakcja z kwotą równą 0 - klient nie jest obciążany, a jedynie potwierdza zgodę na płatności cykliczne kodem BLIK.
Parametry zapytania
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
transactionType | string | Tak | "blik_recurring" |
service | string | Tak | Nazwa serwisu z panelu |
value | string | Tak | Musi być 0 (rejestracja bez obciążenia) |
url_success | string | Tak | URL po udanej rejestracji |
url_fail | string | Tak | URL po nieudanej rejestracji |
url_ipn | string | Tak | URL do powiadomień IPN |
checksum | string | Tak | Suma kontrolna SHA-256 |
blik_code | string | Tak | 6-cyfrowy kod BLIK |
user_ip | string | Tak | Adres IP klienta |
user_agent | string | Tak | Nagłówek User-Agent klienta |
register_blik_recurring_alias | object | Tak | Parametry aliasu PAYID (poniżej) |
alias_ipn_url | string | Nie | Adres URL do powiadomień o zmianach statusu aliasu (max 500 znaków); gdy pominięty, powiadomienia trafiają na url_ipn |
description | string | Nie | Opis subskrypcji |
Obiekt register_blik_recurring_alias
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
label | string | Tak | Etykieta subskrypcji widoczna dla klienta (max 50 znaków) |
type | string | Tak | Typ aliasu - musi być "PAYID" |
model | string | Tak | Model odnowienia: "A", "M" lub "O" |
frequency | string | Tak | Częstotliwość obciążeń: liczba 1-999 + jednostka D (dni), W (tygodnie), M (miesiące), Q (kwartały), Y (lata), np. "1M", "2W", "30D" |
value | string | Nie | Własna wartość aliasu (max 128 znaków). Gdy pominięta, dpay generuje wartość automatycznie |
limit_amt | integer | Nie | Limit pojedynczego obciążenia w groszach (np. 5999 = 59,99 PLN) |
tot_limit_amt | integer | Nie | Łączny limit wszystkich obciążeń w groszach |
is_limit_amt_fixed | boolean | Nie | true - każde obciążenie musi być dokładnie równe limit_amt; false - limit_amt jest kwotą maksymalną |
expiration_date | string | Nie | Data wygaśnięcia aliasu (YYYY-MM-DD, późniejsza niż dzisiejsza) |
init_date | string | Nie | Data pierwszego obciążenia (YYYY-MM-DD, dzisiejsza lub późniejsza) |
Zalecamy przekazanie własnej wartości w register_blik_recurring_alias.value i zapisanie jej po stronie serwera w powiązaniu z kontem klienta - będzie potrzebna do kolejnych obciążeń oraz do sprawdzania statusu aliasu. Wartość musi być unikalna - próba rejestracji drugiego aktywnego aliasu o tej samej wartości zostanie odrzucona.
Generowanie checksum
Checksum generowany jest identycznie jak dla standardowej płatności:
sha256({service}|{SecretHash}|{value}|{url_success}|{url_fail}|{url_ipn})
Kwota w checksumie jest normalizowana do dwóch miejsc po przecinku - dla rejestracji z value: 0 hashuj "0.00".
Przykład zapytania
cURL
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "blik_recurring",
"service": "abc123",
"value": 0,
"url_success": "https://mojsklep.pl/sukces",
"url_fail": "https://mojsklep.pl/blad",
"url_ipn": "https://mojsklep.pl/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",
"description": "Subskrypcja Premium",
"register_blik_recurring_alias": {
"label": "Subskrypcja Premium",
"type": "PAYID",
"value": "SUB-1234567890",
"model": "M",
"frequency": "1M",
"limit_amt": 5999,
"tot_limit_amt": 71988,
"is_limit_amt_fixed": false,
"expiration_date": "2027-07-01"
}
}'
PHP
<?php
$service = getenv('DPAY_SERVICE');
$secretHash = getenv('DPAY_SECRET_HASH');
$value = '0.00';
$urlSuccess = 'https://mojsklep.pl/sukces';
$urlFail = 'https://mojsklep.pl/blad';
$urlIpn = 'https://mojsklep.pl/api/ipn';
$checksum = hash('sha256',
$service . '|' . $secretHash . '|' . $value . '|' .
$urlSuccess . '|' . $urlFail . '|' . $urlIpn
);
$payload = json_encode([
'transactionType' => 'blik_recurring',
'service' => $service,
'value' => 0,
'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'],
'description' => 'Subskrypcja Premium',
'register_blik_recurring_alias' => [
'label' => 'Subskrypcja Premium',
'type' => 'PAYID',
'value' => 'SUB-' . $userId,
'model' => 'M',
'frequency' => '1M',
'limit_amt' => 5999,
'tot_limit_amt' => 71988,
'is_limit_amt_fixed' => false,
],
]);
$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);
Odpowiedź API
{
"error": false,
"msg": "Internal processing",
"status": true,
"transactionId": "abc-def-123-456"
}
Pole status jest wartością logiczną (true/false). Po otrzymaniu tej odpowiedzi klient musi potwierdzić rejestrację subskrypcji w swojej aplikacji bankowej. Wynik rejestracji otrzymasz przez IPN, a aktualny status aliasu sprawdzisz endpointem statusu (poniżej).
Krok 2: Obciążenie cykliczne
Kolejne płatności inicjujesz z serwera - bez kodu BLIK i bez udziału klienta.
Parametry zapytania
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
transactionType | string | Tak | "blik_recurring" |
service | string | Tak | Nazwa serwisu z panelu |
value | string | Tak | Kwota obciążenia w PLN (musi być większa od 0) |
url_success | string | Tak | URL po udanej płatności |
url_fail | string | Tak | URL po nieudanej płatności |
url_ipn | string | Tak | URL do powiadomień IPN |
checksum | string | Tak | Suma kontrolna SHA-256 |
blik_alias | string | Tak | Wartość aliasu PAYID z rejestracji (max 128 znaków) |
no_delay | boolean | Nie | Domyślnie true (odpowiedź natychmiastowa). false - BLIK może wstrzymać transakcję do 72 godzin, czekając na potwierdzenie klienta w aplikacji (modele M/O); wymaga wcześniejszej zgody dpay |
user_ip | string | Nie | Adres IP - opcjonalny przy obciążeniu server-to-server |
user_agent | string | Nie | User-Agent - opcjonalny przy obciążeniu server-to-server |
Przy obciążeniu cyklicznym nie przekazuj blik_code, register_blik_alias ani register_blik_recurring_alias - pole blik_alias wyklucza się z nimi.
Walidacja limitów (model M)
Dla aliasów z modelem M każde obciążenie jest walidowane po stronie dpay:
limit_amtzis_limit_amt_fixed: true- kwota obciążenia musi być dokładnie równa limitowilimit_amtzis_limit_amt_fixed: false- kwota obciążenia nie może przekroczyć limitutot_limit_amt- suma dotychczasowych obciążeń plus bieżące nie może przekroczyć limitu łącznego
Przekroczenie limitu zwraca HTTP 400 z opisem w polu message.
Przykład zapytania
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "blik_recurring",
"service": "abc123",
"value": "59.99",
"url_success": "https://mojsklep.pl/sukces",
"url_fail": "https://mojsklep.pl/blad",
"url_ipn": "https://mojsklep.pl/api/ipn",
"checksum": "e3b0c44298fc1c149afb...",
"blik_alias": "SUB-1234567890"
}'
Odpowiedź API
{
"error": false,
"msg": "Internal processing",
"status": true,
"transactionId": "abc-def-123-456"
}
Wynik obciążenia otrzymasz przez IPN na url_ipn.
Sprawdzanie statusu aliasu
Aktualny status aliasu PAYID (wraz z parametrami rejestracji) pobierzesz dedykowanym endpointem:
POST https://api-payments.dpay.pl/api/v1_0/payments/blik/recurring/status
Content-Type: application/json
Parametry
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
service | string | Tak | Nazwa serwisu z panelu |
alias_value | string | Tak | Wartość aliasu PAYID (max 128 znaków) |
checksum | string | Tak | Suma kontrolna SHA-256 |
Generowanie checksum
sha256({service}|{SecretHash}|{alias_value})
Przykład zapytania
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/blik/recurring/status \
-H "Content-Type: application/json" \
-d '{
"service": "abc123",
"alias_value": "SUB-1234567890",
"checksum": "f5a3b2c1d0..."
}'
Odpowiedź
{
"status": "success",
"data": {
"alias_value": "SUB-1234567890",
"alias_type": "PAYID",
"status": "ACTIVE",
"expiration_date": "2027-07-01",
"registration": {
"model": "M",
"frequency": "1M",
"limit_amt": 5999,
"tot_limit_amt": 71988,
"is_limit_amt_fixed": false,
"init_date": null,
"label": "Subskrypcja Premium",
"registered_at": "2026-07-01T12:00:00+02:00"
}
}
}
| Pole | Typ | Opis |
|---|---|---|
alias_value | string | Wartość aliasu |
alias_type | string | Zawsze "PAYID" |
status | string|null | Aktualny status aliasu, np. "ACTIVE", "INACTIVE", "UNREGISTERED", "EXPIRED" |
expiration_date | string|null | Data wygaśnięcia aliasu |
registration | object|null | Parametry podane przy rejestracji (model, frequency, limity, etykieta, data rejestracji) |
Limity zapytań
| Endpoint | Limit |
|---|---|
POST /payments/register | 120 zapytań/min |
POST /blik/recurring/status | 60 zapytań/min |
Obsługa błędów
Błędy walidacji biznesowej zwracane są z HTTP 400 w formacie {"status": "failed", "message": "...", "errors": {...}}. Najczęstsze komunikaty:
| Komunikat | Przyczyna |
|---|---|
BLIK Recurring is not enabled for this service. | Płatności cykliczne nie są włączone dla serwisu |
BLIK Recurring model M is not enabled for this service. | Wskazany model odnowienia nie jest aktywny |
BLIK Recurring registration requires value=0. | Rejestracja z kwotą inną niż 0 |
An active BLIK Recurring alias with this value already exists. | Duplikat wartości aliasu |
BLIK Recurring payment requires value > 0. | Obciążenie z kwotą 0 |
No active BLIK Recurring alias found for this value. | Alias nie istnieje, wygasł lub został wyrejestrowany |
Setting no_delay=false requires merchant approval (...). Contact support. | Użycie no_delay: false bez zgody dpay |
Odrzucenie płatności przez system BLIK zwraca odpowiedź {"error": true, "msg": "Transaction canceled", "status": false, ...} z kodem w polu additionalInfo.error - lista kodów jest wspólna dla wszystkich płatności BLIK, patrz BLIK OneClick - obsługa błędów.
Jeśli alias wygasł lub klient wycofał zgodę w aplikacji bankowej, przeprowadź ponowną rejestrację aliasu (Krok 1) przy najbliższej okazji - np. przy odnowieniu subskrypcji.