Przejdź do głównej zawartości

BLIK - płatności cykliczne (subskrypcje)

Płatności cykliczne BLIK (w nomenklaturze BLIK: Płatności Powtarzalne) pozwalają obciążać klienta w kolejnych okresach bez podawania kodu BLIK - sprawdzają się przy subskrypcjach, abonamentach i rachunkach. Klient jednorazowo akceptuje płatność powtarzalną w aplikacji banku, a kolejne obciążenia inicjujesz z serwera, podając jej alias.

POST/api/v1_0/payments/registerPełny kontrakt rejestracji: parametry, checksum, kody błędów.Pełny kontrakt w API Reference

Jak to działa?​

  1. Rejestracja płatności powtarzalnej - transakcja z kodem BLIK i obiektem recurring_registration, z kwotą 0 (sama zgoda) albo z opłatą inicjalną, np. za pierwszy okres. Klient widzi w aplikacji banku nazwę i warunki płatności powtarzalnej i jednym potwierdzeniem płaci opłatę inicjalną oraz akceptuje płatność powtarzalną.
  2. Obciążenia - kolejne płatności z polem recurring_alias, wysyłane przez Twój serwer bez kodu BLIK.
  3. Wynik i ponowienie - udane obciążenie potwierdza IPN. Obciążenie odrzucone z przyczyny przejściowej (np. brak środków) możesz ponowić.
  4. Zarządzanie - sprawdzanie statusu, anulowanie oraz powiadomienia o zmianach (np. gdy klient anuluje płatność w aplikacji banku).
Wspólne API płatności powtarzalnych

Pola recurring_registration i recurring_alias oraz endpointy /payments/recurring/* są wspólne dla metod płatności. Obecnie obsługiwaną metodą jest BLIK (methods: ["blik"]), a rejestracja wymaga kodu BLIK.

Modele płatności powtarzalnych​

Model wybierasz przy rejestracji. Decyduje on o tym, kto zatwierdza kolejne obciążenia i jakie warunki klient akceptuje w banku. Każdy model włącza dla Twojego Punktu Płatności dpay.

ModelKto zatwierdza obciążenieKiedy go wybrać
ABank klienta, automatycznie - gdy obciążenie spełnia warunki zaakceptowane przy rejestracji (stała kwota, częstotliwość, limit łączny, okres)Stała kwota w stałym rytmie, np. abonament 59,99 zł co miesiąc
MKlient - potwierdza każde obciążenie w aplikacji bankuZmienne kwoty lub terminy, gdy klient ma zatwierdzać każdą płatność
ONikt - bank obciąża konto bez udziału klienta, jeśli BLIK zakwalifikuje obciążenie jako transakcję inicjowaną przez akceptanta (MIT)Usługi ciągłe o zmiennej kwocie, np. rachunki za media, opłaty za użycie, dopłaty po wykonaniu usługi

Model A - automatyczny​

  • Przy rejestracji podajesz komplet warunków: częstotliwość (frequency), kwotę każdego obciążenia (limit_amt), limit łączny (tot_limit_amt), datę pierwszego obciążenia (init_date) i datę ważności (expiration_date). Klient akceptuje je w aplikacji banku.
  • Kwota jest stała - każde obciążenie musi być równe limit_amt.
  • dpay odrzuca obciążenie o innej kwocie, przekraczające limit łączny albo wysłane przed init_date - zanim trafi ono do BLIK.
  • Częstotliwość sprawdza bank. Obciążenie, które nie spełnia warunków z rejestracji, bank odrzuca z kodem AUTOCONF_REQ_NOT_MET (przy no_delay: false może zamiast tego poprosić klienta o potwierdzenie).

Model M - z potwierdzeniem klienta​

  • Klient potwierdza każde obciążenie w aplikacji banku, więc wynik poznasz dopiero po jego decyzji - nawet po 72 godzinach.
  • no_delay: true jest w tym modelu niedozwolone.
  • frequency, init_date i expiration_date są opcjonalne - trafiają do banku razem z zaproszeniem jako informacja o płatności powtarzalnej.
  • Limity limit_amt, tot_limit_amt i is_limit_amt_fixed są opcjonalne i nie trafiają do banku - pilnuje ich dpay przy każdym obciążeniu.

Model O - bez udziału klienta (MIT)​

  • Przy rejestracji podajesz etykietę, alias, link do warunków i opcjonalnie datę ważności. frequency i limity są w tym modelu zabronione - po ich braku bank rozpoznaje model O.

  • Pojedyncze obciążenie może wynieść najwyżej 2000 zł i musi mieścić się w przedziale kwot aktywnym dla Twojego punktu:

    PrzedziałKwoty
    10 - 400,00 zł
    2400,01 - 1000,00 zł
    31000,01 - 2000,00 zł
  • dpay odrzuca obciążenie powyżej 2000 zł albo w nieaktywnym przedziale (HTTP 400), zanim trafi ono do BLIK.

  • Gdy BLIK nie zakwalifikuje obciążenia jako MIT (np. po czasowym wyłączeniu przedziału), bank odrzuca je z kodem SEC_DECLINED. Przy no_delay: false bank może zamiast tego poprosić klienta o potwierdzenie w aplikacji.

Wymagania dla modelu O
  • Tylko usługi ciągłe: subskrypcje, rachunki (prąd, gaz, internet), opłaty za użytkowanie, dopłaty po wykonaniu usługi, przejazdy i postój. Model O nie służy do jednorazowych zakupów (sklepy internetowe, dostawy jedzenia).
  • Konfiguracja w BLIK: dpay zgłasza Twój punkt do BLIK razem z przedziałami kwot i materiałami z wniosku pokazującymi proces rejestracji (makiety, nagranie lub dostęp testowy). BLIK weryfikuje ten proces i po pozytywnej weryfikacji konfiguruje punkt - zwykle w około 3 dni robocze.
  • Przedziały kwot przyznaje dpay po analizie ryzyka. Rejestracja w modelu O wymaga co najmniej jednego aktywnego przedziału.
  • Kwot nie wolno dzielić na mniejsze obciążenia, żeby zmieścić się w przedziale.

Wymagania​

  • Aktywny Punkt Płatności z włączonym BLIK i uruchomionymi płatnościami cyklicznymi. Wniosek złożysz w panelu dpay: Punkty płatności → usługa → Metody płatności → BLIK - płatności cykliczne. Wybierasz modele (dla modelu O także przedziały kwot), opisujesz usługę, podajesz regulamin i materiały pokazujące proces zgody oraz akceptujesz warunki. Modele A i M uruchamiamy po weryfikacji wniosku, model O dodatkowo po konfiguracji w BLIK (patrz wyżej). O decyzji informujemy e-mailem.
  • Warunki płatności powtarzalnej (regulamin lub umowa) pod stałym adresem URL - patrz link do warunków.
  • Bezpieczne przechowywanie aliasu płatności powtarzalnej po stronie serwera, w powiązaniu z kontem klienta.
  • Dostęp do adresu IP i User-Agent klienta przy rejestracji (wymagane przez regulacje).
  • Proces rejestracji i komunikacja z klientem zgodne z obowiązkami wobec klienta oraz z wymaganiami BLIK dla procesu zakupu (nazwa metody, lista banków, szczegóły płatności przed zapłatą).
Zacznij od trybu testowego

Integrację zbudujesz i przetestujesz bez wniosku - w trybie testowym dostępne są wszystkie modele, a odpowiedzi odtwarzają zachowanie BLIK.

Endpoint​

POST https://api-payments.dpay.pl/api/v1_0/payments/register
Content-Type: application/json

Krok 1: Rejestracja płatności powtarzalnej​

Rejestracja to transakcja z kodem BLIK, która niesie zaproszenie do płatności powtarzalnej. Wysyłaj ją dopiero wtedy, gdy klient na Twojej stronie wyraźnie zdecyduje się na płatność powtarzalną. Kwota rejestracji może wynosić:

  • 0 - klient nie jest obciążany, tylko akceptuje płatność powtarzalną,
  • więcej niż 0 (opłata inicjalna) - np. za pierwszy okres subskrypcji albo aktywację usługi. Klient na jednym ekranie w aplikacji banku, jednym PIN-em, płaci opłatę inicjalną i akceptuje płatność powtarzalną.
Opłata inicjalna

Połączenie pierwszej płatności ze zgodą to jeden krok dla klienta zamiast dwóch - BLIK zaleca taki proces, bo klient nie zamknie aplikacji w przekonaniu, że włączył płatności powtarzalne. Opłata inicjalna to zwykła płatność BLIK potwierdzana PIN-em: nie dotyczą jej przedziały kwot modelu O ani limit 2000 zł, a nie wlicza się do tot_limit_amt. Zwrócisz ją jak każdą płatność - patrz zwroty.

Jeśli bank klienta nie obsługuje płatności powtarzalnych BLIK, BLIK odrzuca całą transakcję (kod ER_PAYID_UNHANDLED) - klient nie zapłaci opłaty inicjalnej bez aktywnej płatności powtarzalnej.

Parametry zapytania​

PoleTypWymaganeOpis
transactionTypestringTak"transfers"
servicestringTakNazwa serwisu z panelu
valuestringTak0 - sama zgoda na płatność powtarzalną; więcej niż 0 - opłata inicjalna pobierana razem ze zgodą
url_successstringTakURL po udanej rejestracji
url_failstringTakURL po nieudanej rejestracji
url_ipnstringNieURL do powiadomień IPN; bez niego IPN nie jest wysyłany (wynik dostaniesz webhookiem)
checksumstringTakSuma kontrolna SHA-256
blik_codestringTak6-cyfrowy kod BLIK
user_ipstringTakAdres IP klienta
user_agentstringTakNagłówek User-Agent klienta
recurring_registrationobjectTakWarunki płatności powtarzalnej (poniżej)
alias_ipn_urlstringNieAdres URL do powiadomień o zmianach (max 500 znaków); gdy pominięty, powiadomienia trafiają na url_ipn
descriptionstringNieOpis transakcji rejestrującej, przekazywany do BLIK (pierwsze 35 znaków). Bez opisu BLIK dostaje nazwę płatności powtarzalnej (label)

Obiekt recurring_registration​

Wymagalność pól zależy od modelu. Pole oznaczone jako zabronione powoduje błąd walidacji (HTTP 422).

PoleTypAMOOpis
labelstringTakTakTakNazwa płatności powtarzalnej widoczna dla klienta w aplikacji banku (max 35 znaków - limit BLIK), np. "Abonament Premium". Zasady tworzenia etykiety: wymagania BLIK
modelstringTakTakTakModel: "A", "M" lub "O"
terms_urlstringTakTakTakLink do warunków płatności powtarzalnej, które akceptuje klient (max 2048 znaków) - patrz link do warunków
terms_versionstringNieNieNieWersja warunków, np. "2026-09" (max 64 znaki)
aliasstringZalecaneZalecaneZalecaneTwój identyfikator płatności powtarzalnej (max 128 znaków), unikalny w ramach serwisu - patrz uwaga poniżej
methodsarrayNieNieNieMetody, którymi klient opłaca płatność powtarzalną. Obecnie tylko ["blik"] (domyślnie)
frequencystringTakNieZabronioneCzęstotliwość: liczba 1-999 i jednostka D (dni), W (tygodnie), M (miesiące) lub Y (lata), np. "1M", "2W", "30D"
limit_amtintegerTakNieZabronioneKwota w groszach (np. 5999 = 59,99 zł). Model A: kwota każdego obciążenia. Model M: maksymalna kwota obciążenia (albo dokładna, gdy is_limit_amt_fixed: true)
tot_limit_amtintegerTakNieZabronioneŁączny limit obciążeń cyklicznych w groszach (bez opłaty inicjalnej)
is_limit_amt_fixedbooleanNieNieZabronioneModel M: true - każde obciążenie musi być równe limit_amt, false - limit_amt jest kwotą maksymalną. W modelu A kwota jest zawsze stała - możesz pominąć pole albo podać true
init_datestringTakNie-Data pierwszego obciążenia cyklicznego (YYYY-MM-DD, dzisiejsza lub późniejsza) - gdy opłata inicjalna pokrywa pierwszy okres, podaj początek kolejnego. W modelu A obciążenie przed tą datą zostanie odrzucone. W modelu O pole jest pomijane
expiration_datestringTakNieNieData ważności płatności powtarzalnej (YYYY-MM-DD, późniejsza niż dzisiejsza, najpóźniej 10 lat od dziś). Bez daty jest ważna do odwołania
Podaj własny alias

Przekaż własny identyfikator w recurring_registration.alias (np. "SUB-12345") i zapisz go po stronie serwera w powiązaniu z kontem klienta. Będzie potrzebny do obciążeń, sprawdzania statusu i anulowania. Gdy go pominiesz, dpay nada alias sam i zwróci go w odpowiedzi w polu additionalInfo.recurring_registration.alias - ale jeśli odpowiedź do Ciebie nie dotrze (np. timeout), nie poznasz go. Rejestracja drugiej aktywnej płatności powtarzalnej z tym samym aliasem zostanie odrzucona.

Pole terms_url jest wymagane. To link do dokumentu z warunkami płatności powtarzalnej, które klient akceptuje przy rejestracji - regulaminu usługi, umowy albo cennika. dpay zapisuje go razem z terms_version i zwraca w statusie płatności powtarzalnej. Przy reklamacji to dowód, na jakie warunki zgodził się klient.

  • Treść pod linkiem nie może się zmieniać. Gdy zmieniasz warunki, opublikuj nowy dokument pod nowym adresem (z nową terms_version) i używaj go w kolejnych rejestracjach. Poprzedni dokument zostaw bez zmian - klienci zarejestrowani wcześniej zaakceptowali jego treść.

  • Może to być umowa wygenerowana dla konkretnego klienta. Link do indywidualnego dokumentu często zawiera identyfikator umowy, sumy kontrolne albo UUID. dpay przyjmuje linki do 2048 znaków, np.:

    https://mojsklep.pl/umowy/9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08/2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae/0b5c3e2a-7f7d-4f1e-9d1c-3a2b1c0d9e8f
  • Dostępność - dokument powinien otwierać się bez logowania i pozostać dostępny co najmniej 13 miesięcy od ostatniego obciążenia (tyle czasu klient ma na reklamację).

Generowanie checksum​

Checksum generowany jest identycznie jak dla standardowej płatności:

sha256({service}|{SecretHash}|{value}|{url_success}|{url_fail}|{url_ipn})
Format kwoty w checksum

Kwota w checksumie jest normalizowana do dwóch miejsc po przecinku - dla rejestracji z value: 0 hashuj "0.00".

Przykład zapytania​

cURL (model A, pierwszy miesiąc w opłacie inicjalnej)​

Klient płaci przy rejestracji 59,99 zł za październik, a kolejne obciążenia po 59,99 zł idą co miesiąc od 1 listopada.

curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "transfers",
"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_code": "123456",
"user_ip": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"description": "Abonament Premium",
"recurring_registration": {
"label": "Abonament Premium",
"alias": "SUB-1234567890",
"model": "A",
"frequency": "1M",
"limit_amt": 5999,
"tot_limit_amt": 71988,
"init_date": "2026-11-01",
"expiration_date": "2027-09-30",
"terms_url": "https://mojsklep.pl/regulamin/2026-09",
"terms_version": "2026-09"
}
}'

PHP (model O, sama zgoda, indywidualna umowa)​

<?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
);

// Umowa wygenerowana dla klienta - treść pod tym adresem nie może się już zmienić
$agreementUrl = 'https://mojsklep.pl/umowy/' . $agreement->uuid . '/' . $agreement->checksum;

$payload = json_encode([
'transactionType' => 'transfers',
'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' => 'Rachunek za energię',
'recurring_registration' => [
'label' => 'Energia - umowa 2026/123',
'alias' => 'ENERGIA-' . $customerId,
'model' => 'O',
'terms_url' => $agreementUrl,
'terms_version' => '2026/123',
],
]);

$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);

W modelu M obiekt rejestracji może zawierać same pola wymagane albo dodatkowo informacje dla klienta i limity pilnowane przez dpay:

{
"label": "Doładowania konta",
"alias": "TOPUP-1234567890",
"model": "M",
"frequency": "1M",
"limit_amt": 20000,
"is_limit_amt_fixed": false,
"terms_url": "https://mojsklep.pl/regulamin/2026-09"
}

Odpowiedź API​

{
"error": false,
"msg": "Internal processing",
"status": true,
"transactionId": "abc-def-123-456",
"additionalInfo": {
"recurring_registration": {
"alias": "SUB-1234567890",
"methods": ["blik"]
}
}
}

Pole status jest wartością logiczną (true/false). Zapisz transactionId (identyfikator transakcji rejestrującej) oraz additionalInfo.recurring_registration.alias - alias, który podasz w polu recurring_alias przy obciążeniach. Po tej odpowiedzi klient akceptuje płatność powtarzalną w aplikacji banku.

Jeśli rejestracja zostanie odrzucona od razu, odpowiedź ma postać {"error": true, "msg": "Transaction canceled", "status": false, ...}, a kod odmowy znajdziesz w polu additionalInfo.error.

Wynik rejestracji​

  • Akceptacja - dostaniesz powiadomienie o zmianie z change_type: "ALIAS_REGISTER", a transakcja rejestracyjna przejdzie w status paid (dostaniesz dla niej standardowy IPN z kwotą opłaty inicjalnej albo 0). Od tej chwili możesz obciążać klienta.
  • Odrzucenie lub brak akceptacji - płatność powtarzalna nie zostanie aktywowana, opłata inicjalna nie zostanie pobrana, a transakcja rejestracyjna przejdzie w status expired (bez IPN). Aktualny stan sprawdzisz endpointem statusu.

Krok 2: Obciążenie cykliczne​

Kolejne płatności inicjujesz z serwera - bez kodu BLIK i bez udziału klienta (w modelu M klient potwierdza je w aplikacji banku).

Parametry zapytania​

PoleTypWymaganeOpis
transactionTypestringTak"transfers"
servicestringTakNazwa serwisu z panelu
valuestringTakKwota obciążenia w PLN (musi być większa od 0)
url_successstringTakURL po udanej płatności
url_failstringTakURL po nieudanej płatności
url_ipnstringNieURL do powiadomień IPN; bez niego IPN nie jest wysyłany (wynik dostaniesz webhookiem)
checksumstringTakSuma kontrolna SHA-256 z kwotą obciążenia i aliasem na końcu (patrz niżej)
recurring_aliasstringTakAlias płatności powtarzalnej z rejestracji (Twoje recurring_registration.alias, zwrócone też w additionalInfo.recurring_registration.alias; max 128 znaków)
no_delaybooleanNieDomyślnie true - bank odpowiada od razu, bez czekania na klienta. false - bank może wstrzymać obciążenie do 72 godzin i poprosić klienta o potwierdzenie w aplikacji; wymaga wcześniejszej zgody dpay. W modelu M pomiń to pole - true zostanie odrzucone
descriptionstringNieOpis obciążenia, np. "Abonament Premium 10/2026". Bank pokazuje go klientowi w historii rachunku - BLIK przyjmuje pierwsze 35 znaków. Bez opisu klient zobaczy nazwę płatności powtarzalnej (label)
user_ipstringNieAdres IP - opcjonalny przy obciążeniu server-to-server
user_agentstringNieUser-Agent - opcjonalny przy obciążeniu server-to-server
Wykluczanie pól

Przy obciążeniu nie przekazuj blik_code, blik_alias, register_blik_alias ani recurring_registration - pole recurring_alias wyklucza się z nimi. Pola recurring_registration i recurring_alias działają tylko z transactionType: "transfers".

Generowanie checksum obciążenia​

sha256({service}|{SecretHash}|{value}|{url_success}|{url_fail}|{url_ipn}|{recurring_alias})

Alias na końcu wiąże obciążenie z konkretnym klientem: suma bez aliasu albo z innym aliasem zostanie odrzucona (Invalid checksum). Bez url_ipn zostaw pusty segment: ...|{url_fail}||{recurring_alias}.

Walidacja przed wysłaniem do BLIK​

Zanim obciążenie trafi do BLIK, dpay sprawdza:

  • płatność powtarzalną - musi być zarejestrowana w Twoim serwisie i aktywna (dpay sprawdza jej bieżący status, np. czy klient nie anulował jej w aplikacji banku),
  • model A - kwota równa limit_amt, suma udanych obciążeń z bieżącym nie większa niż tot_limit_amt, obciążenie nie wcześniej niż init_date,
  • model M - limity podane przy rejestracji (jeśli zostały podane),
  • model O - kwota najwyżej 2000 zł i w aktywnym przedziale.

Naruszenie zwraca HTTP 400 z opisem w polu message (patrz obsługa błędów). Nic nie trafia wtedy do BLIK, a klient nie jest obciążany.

Przykład zapytania​

curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "transfers",
"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...",
"recurring_alias": "SUB-1234567890",
"description": "Abonament Premium 11/2026"
}'

Odpowiedź API​

{
"error": false,
"msg": "Internal processing",
"status": true,
"transactionId": "abc-def-123-456"
}

Obciążenie zostało przekazane do banku. Zapisz transactionId - będzie potrzebny do sprawdzenia statusu i ewentualnego ponowienia.

Jeśli obciążenie zostanie odrzucone od razu, odpowiedź ma postać {"error": true, "msg": "Transaction canceled", "status": false, ...}, a kod odmowy znajdziesz w polu additionalInfo.error (z opisem w additionalInfo.error_description).

Wynik obciążenia​

WynikStatus transakcjiPowiadomienie
Obciążenie udanepaidIPN transfer na url_ipn - jak dla każdej płatności
Obciążenie odrzuconeexpiredBrak IPN

Przy no_delay: true wynik jest zwykle znany po kilku sekundach. W modelu M oraz przy no_delay: false bank może czekać na klienta do 72 godzin.

Transakcje odrzucone nie generują IPN, dlatego sprawdzaj status obciążeń, dla których IPN nie dotarł w oczekiwanym czasie - zapytaniem o status transakcji. Po statusie expired możesz spróbować ponowić obciążenie - odpowiedź powie, czy kod odmowy na to pozwala.

Kody odmowy​

Najczęstsze kody odmowy (w additionalInfo.error odpowiedzi na rejestrację lub obciążenie albo w odpowiedzi endpointu ponowienia):

KodZnaczenieCo zrobić
INSUFFICIENT_FUNDSBrak środków na koncie klientaPonów obciążenie lub spróbuj później nowym
LIMIT_EXCEEDEDPrzekroczony limit transakcji w banku klientaPonów obciążenie lub poinformuj klienta
SYSTEM_ERROR, GENERAL_ERROR, ISS_OUTOFSERVICEChwilowy problem techniczny po stronie banku lub BLIKPonów obciążenie
USER_DECLINEDKlient odrzucił obciążenie w aplikacji bankuNie ponawiaj - skontaktuj się z klientem
TIMEOUTKlient nie potwierdził obciążenia na czasNie ponawiaj - utwórz nowe obciążenie
AUTOCONF_REQ_NOT_METModel A: obciążenie niezgodne z warunkami z rejestracji (kwota, termin, częstotliwość)Sprawdź kwotę i harmonogram obciążeń
SEC_DECLINEDModel O: BLIK nie zakwalifikował obciążenia jako MITSkontaktuj się z BOK dpay; klient może zapłacić kodem BLIK
ALIAS_DECLINEDPłatność powtarzalna została odrzucona lub anulowanaZaproponuj klientowi ponowną rejestrację
ALIAS_NOT_FOUNDPłatność powtarzalna nie istnieje po stronie BLIKZaproponuj klientowi ponowną rejestrację
RECURRING_NOT_ENABLEDModel płatności powtarzalnej nie jest włączony dla Twojego punktuSkontaktuj się z BOK dpay
AMOUNT_LIMIT_EXCEEDEDKwota przekracza maksymalną kwotę obciążeniaSprawdź kwotę
ER_PAYID_UNHANDLEDRejestracja: bank klienta nie obsługuje płatności powtarzalnych BLIK, transakcja odrzucona w całościZaproponuj klientowi inną metodę płatności
WRONG_TICKET_BLOCKEDRejestracja: płatności kodem BLIK chwilowo zatrzymane po serii błędnych kodów (kod nadaje dpay)Poproś klienta o ponowną próbę później - patrz ochrona przed atakiem Wrong Ticket
INTERNAL_ERRORWynik nieznany (błąd komunikacji)Sprawdź status transakcji przed kolejną próbą

Ponowienie odrzuconego obciążenia​

BLIK pozwala ponowić odrzucone obciążenie z tym samym identyfikatorem transakcji, co wyklucza podwójne pobranie środków. Służy do tego osobny endpoint - nie wysyłaj ponownie tego samego obciążenia przez payments/register, bo to nowa transakcja.

Zasady ponowienia:

  • ponowić można tylko obciążenie odrzucone z kodem INSUFFICIENT_FUNDS, LIMIT_EXCEEDED, SYSTEM_ERROR, GENERAL_ERROR lub ISS_OUTOFSERVICE,
  • najwyżej 3 ponowienia w ciągu 5 minut od utworzenia pierwotnego obciążenia,
  • po upływie tego czasu utwórz nowe obciążenie (krok 2),
  • dpay sprawdza płatność powtarzalną i kwotę tak samo jak przy pierwszym obciążeniu.
POST/api/v1_0/payments/recurring/retryPełny kontrakt ponowienia odrzuconego obciążenia.Pełny kontrakt w API Reference

Endpoint​

POST https://api-payments.dpay.pl/api/v1_0/payments/recurring/retry
Content-Type: application/json

Parametry​

PoleTypWymaganeOpis
servicestringTakNazwa serwisu z panelu
transaction_idstringTaktransactionId z odpowiedzi na obciążenie (max 64 znaki)
checksumstringTakSuma kontrolna SHA-256

Generowanie checksum​

sha256({service}|{SecretHash}|{transaction_id})

Przykład zapytania​

curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/recurring/retry \
-H "Content-Type: application/json" \
-d '{
"service": "abc123",
"transaction_id": "abc-def-123-456",
"checksum": "9c1b4f2e7a..."
}'

Odpowiedź - ponowienie wysłane​

{
"status": "success",
"data": {
"transactionId": "abc-def-123-456",
"retry": {
"status": "pending",
"count": 1
}
}
}
PoleOpis
retry.statuspending - ponowienie trafiło do banku, wynik przyjdzie jak dla obciążenia (IPN przy sukcesie, status expired przy odmowie). failed - BLIK odrzucił ponowienie od razu, transakcja pozostaje expired
retry.countNumer ponowienia (1-3)
retry.error, retry.error_descriptionKod i opis odmowy - tylko przy failed

Odpowiedź - ponowienie niedozwolone​

Gdy ponowienie nie jest dozwolone, API zwraca HTTP 400 i nic nie trafia do BLIK:

{
"status": "failed",
"message": "Recurring charge cannot be retried (DECLINE_NOT_RETRYABLE).",
"errors": {
"retry": "DECLINE_NOT_RETRYABLE",
"decline_reason": "USER_DECLINED"
}
}
Kod w errors.retryZnaczenieCo zrobić
PAYMENT_NOT_DECLINEDObciążenie nie zostało odrzucone - jest w toku albo zakończyło się sukcesemPoczekaj na wynik
DECLINE_NOT_RETRYABLEKod odmowy (w errors.decline_reason) nie pozwala na ponowieniePostępuj według kodu odmowy
RETRY_LIMIT_REACHEDWykorzystano limit ponowieńUtwórz nowe obciążenie
RETRY_WINDOW_EXPIREDMinęło 5 minut od pierwotnego obciążeniaUtwórz nowe obciążenie
ALIAS_NOT_AVAILABLEPłatność powtarzalna nie jest już aktywnaZaproponuj klientowi ponowną rejestrację
RECURRING_NOT_ENABLEDModel płatności powtarzalnej nie jest włączony dla Twojego punktuSkontaktuj się z BOK dpay
PAYMENT_NOT_FOUNDNie znaleziono obciążenia w systemie BLIKSprawdź transaction_id
Service unavailableChwilowy brak połączenia z systemem BLIKWywołaj ponowienie jeszcze raz za chwilę

Pozostałe błędy mają klucz odpowiadający polu: errors.transaction_id (Transaction not found, Not a recurring charge, Transaction already paid, Transaction not retryable), errors.recurring_alias (Alias not found, Alias not active) oraz komunikaty walidacji kwoty jak przy obciążeniu.

Sprawdzanie statusu płatności powtarzalnej​

Aktualny status płatności powtarzalnej (wraz z warunkami z rejestracji) pobierzesz endpointem statusu:

POST https://api-payments.dpay.pl/api/v1_0/payments/recurring/status
Content-Type: application/json
POST/api/v1_0/payments/recurring/statusPełny kontrakt: status płatności powtarzalnej i warunki rejestracji.Pełny kontrakt w API Reference

Parametry​

PoleTypWymaganeOpis
servicestringTakNazwa serwisu z panelu
aliasstringTakAlias płatności powtarzalnej (max 128 znaków)
checksumstringTakSuma kontrolna SHA-256

Generowanie checksum​

sha256({service}|{SecretHash}|{alias})

Przykład zapytania​

curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/recurring/status \
-H "Content-Type: application/json" \
-d '{
"service": "abc123",
"alias": "SUB-1234567890",
"checksum": "f5a3b2c1d0..."
}'

Odpowiedź​

{
"status": "success",
"data": {
"alias": "SUB-1234567890",
"method": "blik",
"status": "ACTIVE",
"expiration_date": "2027-09-30",
"registration": {
"transaction_id": "abc-def-123-456",
"label": "Abonament Premium",
"model": "A",
"frequency": "1M",
"limit_amt": 5999,
"tot_limit_amt": 71988,
"is_limit_amt_fixed": true,
"init_date": "2026-11-01",
"terms_url": "https://mojsklep.pl/regulamin/2026-09",
"terms_version": "2026-09",
"registered_at": "2026-09-26T12:00:00+02:00"
}
}
}
PoleTypOpis
aliasstringAlias płatności powtarzalnej
methodstringMetoda płatności - "blik"
statusstring|nullAktualny status: "ACTIVE" (można obciążać), "INACTIVE" (rejestracja nie została jeszcze zaakceptowana), "UNREGISTERED" (anulowana przez Ciebie lub klienta), "EXPIRED" (minęła data ważności), "DECLINED" (rejestracja odrzucona)
expiration_datestring|nullData ważności
registrationobjectWarunki z rejestracji: transaction_id transakcji rejestrującej, label, model, frequency, limity, init_date, terms_url, terms_version i data rejestracji (registered_at). Pola niepodane przy rejestracji mają wartość null

Gdy w Twoim serwisie nie zarejestrowano płatności powtarzalnej z tym aliasem, API zwraca HTTP 400 z errors.alias: Alias not found.

Anulowanie płatności powtarzalnej​

Anuluj płatność powtarzalną, gdy klient zrezygnuje z usługi w Twoim serwisie albo gdy zastępujesz ją nową (np. przy zmianie planu lub wygasaniu ważności - ważności nie da się przedłużyć). W takim przypadku najpierw zarejestruj nową płatność powtarzalną, a po jej aktywacji anuluj starą. Po anulowaniu obciążenia z tym aliasem są odrzucane.

POST/api/v1_0/payments/recurring/cancelPełny kontrakt anulowania płatności powtarzalnej.Pełny kontrakt w API Reference

Endpoint​

POST https://api-payments.dpay.pl/api/v1_0/payments/recurring/cancel
Content-Type: application/json

Parametry​

PoleTypWymaganeOpis
servicestringTakNazwa serwisu z panelu
aliasstringTakAlias płatności powtarzalnej (max 128 znaków)
reasonstringNiePowód anulowania (max 255 znaków)
checksumstringTakSuma kontrolna SHA-256

Generowanie checksum​

sha256({service}|{SecretHash}|{alias}|cancel)

Stały napis cancel na końcu odróżnia anulowanie od zapytania o status - sumą ze statusu nie da się anulować płatności powtarzalnej.

Przykład zapytania​

curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/recurring/cancel \
-H "Content-Type: application/json" \
-d '{
"service": "abc123",
"alias": "SUB-1234567890",
"reason": "Rezygnacja z abonamentu",
"checksum": "f5a3b2c1d0..."
}'

Odpowiedź​

{
"status": "success",
"data": {
"alias": "SUB-1234567890",
"status": "UNREGISTERED"
}
}

Błędy zwracane są z HTTP 400. W errors.cancel znajdziesz Alias not found (brak aktywnej płatności powtarzalnej z tym aliasem), kod błędu BLIK albo Service unavailable (spróbuj ponownie za chwilę).

Powiadomienia o zmianach płatności powtarzalnej​

Przy każdej zmianie statusu płatności powtarzalnej dpay.pl wysyła powiadomienie alias_update na alias_ipn_url (lub url_ipn, gdy go nie podano). Format powiadomienia, weryfikacja podpisu i zasady ponawiania są takie same jak dla BLIK OneClick - patrz powiadomienia o aliasie. Dla płatności powtarzalnej alias_type ma wartość "PAYID".

change_typeZnaczenieCo zrobić
ALIAS_REGISTERKlient zaakceptował płatność powtarzalną - jest aktywnaOznacz ją jako aktywną i planuj obciążenia
ALIAS_UPDATEZmiana danych płatności powtarzalnejOdśwież status endpointem statusu
ALIAS_UNREGISTERPłatność powtarzalna anulowana - przez Ciebie albo przez klienta w aplikacji bankuWstrzymaj obciążenia; jeśli klient nie zrezygnował z usługi, zaproponuj nową płatność powtarzalną
ALIAS_EXPIREDMinęła data ważnościWstrzymaj obciążenia i zaproponuj nową płatność powtarzalną
ALIAS_DECLINEDRejestracja została odrzuconaNie obciążaj klienta
Identyfikacja płatności powtarzalnej w powiadomieniu

Powiadomienie skorelujesz po polu id - to transactionId transakcji rejestrującej. Pole alias_key zawiera identyfikator w systemie BLIK, który nie jest równy Twojemu aliasowi (recurring_registration.alias).

Obowiązki wobec klienta​

Płatności powtarzalne BLIK podlegają zasadom reklamacji BLIK - klient może zakwestionować obciążenie w swoim banku nawet do 13 miesięcy od autoryzacji. Najczęstsze podstawy reklamacji to brak zgody, niejasne warunki, obciążenie po anulowaniu i brak wymaganej informacji przed płatnością. Dlatego:

  • Zgoda - wysyłaj rejestrację dopiero po wyraźnym działaniu klienta na Twojej stronie. Warunki i cenę pokaż wyraźnie, oddzielnie od innych treści.
  • Warunki - w terms_url podawaj dokument, który klient faktycznie zaakceptował, i nie zmieniaj jego treści - patrz link do warunków.
  • Proces zakupu - nazwa „Płatności Powtarzalne BLIK”, lista obsługujących banków i szczegóły płatności przed podaniem kodu - patrz wymagania BLIK.
  • Etykieta - label powinien jednoznacznie wskazywać usługę. Klient widzi go w aplikacji banku na liście swoich płatności powtarzalnych - patrz zasady tworzenia etykiety.
  • Informowanie - poinformuj klienta co najmniej 14 dni przed pierwszym płatnym okresem, 30 dni przed odnowieniem i 14 dni przed zmianą ceny.
  • Obciążenia - obciążaj tylko w granicach umowy z klientem. Do ponawiania odmów używaj endpointu ponowienia.
  • Rezygnacja - umożliw łatwe anulowanie w Twoim serwisie. Po rezygnacji nie obciążaj klienta i anuluj płatność powtarzalną.
  • Dowody - przechowuj co najmniej 13 miesięcy od ostatniego obciążenia: potwierdzenie zgody (data, adres IP, wersja warunków), korespondencję z klientem i historię anulowań. dpay poprosi o nie przy reklamacji.

Reklamacje i zgłoszenia fraudu​

Klient może zakwestionować obciążenie w swoim banku (reklamacja), a bank może zgłosić płatność jako oszukańczą. Sprawa pojawia się w panelu w zakładce Spory, a Ty dostajesz e-mail z terminem na odpowiedź:

SprawaTwój terminTermin dpay wobec BLIK
Reklamacja5 dni kalendarzowych15 dni - brak stanowiska oznacza uznanie reklamacji
Zgłoszenie fraudu1 dzień roboczynastępny dzień roboczy
  • dpay sam uzupełnia zapis zgody z rejestracji (data, warunki, adres IP i przeglądarka klienta), historię obciążeń i status płatności cyklicznej. Ty dosyłasz ekran zgody i powiadomienia wysłane klientowi przed obciążeniem - bez nich obrona przed zarzutem braku zgody albo braku informacji jest bardzo trudna.
  • Uznana reklamacja oznacza korektę: kwota wraca do banku klienta i schodzi z Twojego salda. Przy fraudzie, gdy środki są jeszcze na saldzie, zwracamy je bankowi korektą z dobrej woli.
  • Po korekcie dpay może w ciągu 30 dni wnieść o arbitraż. Wygrany arbitraż zwraca korektę na saldo.

Opłaty (netto, potrącane z salda):

PozycjaKwota
Obsługa każdej reklamacji50 zł
Uznana reklamacja100 zł
Przegrany arbitraż1000 zł

Do kwot doliczamy VAT. Opłatę za obsługę naliczamy za każdą reklamację, niezależnie od wyniku. Opłaty za uznaną reklamację i przegrany arbitraż (obejmują opłaty BLIK) ponosisz tylko wtedy, gdy przegrasz - przy wygranej ich nie ma.

Testowanie w trybie testowym​

W trybie testowym przetestujesz całą integrację płatności cyklicznych - rejestrację, obciążenia, odmowy, ponowienia, status, anulowanie i powiadomienia - bez prawdziwych pieniędzy. dpay nie łączy się wtedy z BLIK: odpowiedzi daje nasz symulator, który odtwarza zachowanie BLIK sprawdzone w testach na środowisku testowym BLIK i w certyfikacji.

  • Włącz Tryb testowy serwisu w panelu - patrz środowisko testowe.
  • Wniosek nie jest potrzebny: w trybie testowym dostępne są wszystkie modele (A, M i O), wszystkie przedziały kwot modelu O i no_delay: false. Walidacja pól, sumy kontrolne, limit 2000 zł i limity modelu A działają jak na produkcji.
  • Zapytania, odpowiedzi, IPN i webhooki mają ten sam format co na produkcji. Webhooki z trybu testowego mają livemode: false.
  • Płatność powtarzalna zarejestrowana w trybie testowym działa tylko w nim. Po wyłączeniu trybu testowego obciążenie jej aliasu zwróci Alias not found - klientów rejestrujesz na produkcji od nowa.
  • Czasy w tabelach są przybliżone - wyniki przychodzą asynchronicznie, jak z banku.

Rejestracja​

Wynik rejestracji zależy od kodu w blik_code:

Kod BLIKWynik
777200Sukces - transakcja opłacona po ok. 5 s, a po kolejnych ok. 5 s płatność powtarzalna jest aktywna
777201Sukces po dłuższym czekaniu na klienta (ok. 10 s)
777400Klient odrzucił płatność w aplikacji banku (USER_DECLINED)
777401Klient nie potwierdził na czas (TIMEOUT)
777402Brak środków na opłatę inicjalną (INSUFFICIENT_FUNDS)
777500Błąd systemu (SYSTEM_ERROR)
777000Bank klienta nie obsługuje płatności powtarzalnych (ER_PAYID_UNHANDLED) - przetestuj na nim ekran błędu wymagany przez BLIK
Każdy inny kodSukces, jak dla 777200
  • Sukces - transakcja rejestrująca przechodzi na paid (IPN transfer, webhook payment.succeeded), a potem płatność powtarzalna na ACTIVE: dostajesz powiadomienie alias_update z change_type: "ALIAS_REGISTER" i webhook recurring_payment.activated. Pole alias_key ma w trybie testowym postać DPAY.PAYID.0.....
  • Odmowa - odpowiedź od razu z kodem w additionalInfo.error, transakcja expired, płatność powtarzalna w statusie DECLINED i webhook recurring_payment.declined.

Obciążenia​

Obciążenie odpowiada od razu Internal processing, a wynik zależy od kwoty - tak jak w środowisku testowym BLIK, które dobiera odpowiedź banku po kwocie:

KwotaWynikPonowienie
60,73 złOdmowa INSUFFICIENT_FUNDSDozwolone, kończy się sukcesem
60,74 złOdmowa LIMIT_EXCEEDEDDozwolone, kończy się sukcesem
60,78 złOdmowa SYSTEM_ERRORDozwolone, kończy się sukcesem
60,79 złOdmowa INSUFFICIENT_FUNDS przy każdej próbieDozwolone - czwarte ponowienie zwraca RETRY_LIMIT_REACHED
60,75 złOdmowa TIMEOUTNiedozwolone (DECLINE_NOT_RETRYABLE)
60,76 złOdmowa SEC_DECLINED - obciążenie nie zakwalifikowane jako MITNiedozwolone
60,77 złOdmowa USER_DECLINED - klient odrzucił obciążenie w aplikacjiNiedozwolone
60,65 złSukces po ok. 60 s - jak po potwierdzeniu przez klienta (model M, no_delay: false)-
2,37 złSukces, a po ok. 5 s klient usuwa płatność powtarzalną w aplikacji banku-
Każda inna kwotaSukces po ok. 5 s-
  • Sukces - status paid, IPN transfer i webhook payment.succeeded.
  • Odmowa - status expired, bez IPN, webhook payment.failed z kodem odmowy (np. failure.code: "insufficient_funds", failure.provider_code: "INSUFFICIENT_FUNDS").
  • 2,37 zł - po udanym obciążeniu płatność powtarzalna przechodzi na UNREGISTERED: dostajesz alias_update z change_type: "ALIAS_UNREGISTER" i webhook recurring_payment.canceled z canceled_by: "customer". Kolejne obciążenie zwróci Alias not active.
  • Kwota musi przejść walidację modelu. W modelu A obciążenie musi być równe limit_amt - do testu odmowy zarejestruj płatność z limit_amt: 6073.

Ponowienia, status, anulowanie i wygaśnięcie​

  • Ponowienie - te same zasady i kody co na produkcji: tylko odmowy z listy, najwyżej 3 ponowienia w ciągu 5 minut od obciążenia. Wynik ponowienia przychodzi po ok. 5 s.
  • Status - INACTIVE do aktywacji, potem ACTIVE, UNREGISTERED, EXPIRED albo DECLINED.
  • Anulowanie - status UNREGISTERED od razu i webhook recurring_payment.canceled z canceled_by: "merchant". Tak jak w BLIK, po anulowaniu przez Ciebie nie przychodzi alias_update.
  • Wygaśnięcie - płatność powtarzalna z expiration_date wygasa po tej dacie. Status EXPIRED, alias_update z change_type: "ALIAS_EXPIRED" i webhook recurring_payment.expired dostaniesz przy pierwszym obciążeniu albo zapytaniu o status po tej dacie.
  • Zwroty - udane obciążenia testowe zwrócisz jak każdą płatność w trybie testowym.

Limity zapytań​

EndpointLimit
POST /payments/register120 zapytań/min
POST /payments/recurring/status60 zapytań/min
POST /payments/recurring/retry30 zapytań/min
POST /payments/recurring/cancel30 zapytań/min

Obsługa błędów​

Błędy walidacji pól (np. recurring_registration.frequency w modelu O, brak recurring_registration.init_date w modelu A albo brak recurring_registration.terms_url) zwracane są z HTTP 422 z listą pól w errors. Błędy walidacji biznesowej zwracane są z HTTP 400 w formacie {"status": "failed", "message": "...", "errors": {...}}. Najczęstsze komunikaty:

KomunikatPrzyczyna
Recurring payments are 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 nie jest aktywny dla serwisu
BLIK Recurring model O requires at least one active amount range for this service. Contact dpay support.Model O bez aktywnego przedziału kwot
An active recurring payment with this alias already exists.Aktywna płatność powtarzalna z tym aliasem już istnieje (errors.alias: Alias already active)
Recurring charge requires value > 0.Obciążenie z kwotą 0
No recurring payment registered for this alias.Płatność powtarzalna z tym aliasem nie była rejestrowana w tym serwisie (errors.recurring_alias: Alias not found)
Recurring payment is not active (status: ...).Płatność powtarzalna wygasła, została anulowana albo rejestracja nie została zaakceptowana (errors.recurring_alias: Alias not active)
BLIK Recurring model M does not allow no_delay=true: ...no_delay: true dla płatności powtarzalnej w modelu M
Setting no_delay=false requires merchant approval (...). Contact support.Użycie no_delay: false bez zgody dpay
BLIK Recurring: payment amount must be exactly ... PLN (fixed limit).Kwota różna od stałej kwoty z rejestracji (model A lub M z is_limit_amt_fixed: true)
BLIK Recurring: payment amount ... PLN exceeds single payment limit ... PLN.Model M: przekroczony limit pojedynczego obciążenia
BLIK Recurring: total spent ... PLN + requested ... PLN exceeds total limit ... PLN.Przekroczony limit łączny tot_limit_amt
BLIK Recurring model A: the first payment is scheduled for ....Model A: obciążenie przed init_date
BLIK Recurring model O: payment amount ... PLN exceeds the maximum of 2000.00 PLN.Model O: kwota powyżej 2000 zł
BLIK Recurring model O: payment amount ... PLN is in the ... range, which is not active for this service. Contact dpay support.Model O: kwota w nieaktywnym przedziale

Odmowy banku i systemu BLIK opisuje sekcja kody odmowy.

wskazówka

Jeśli płatność powtarzalna wygasła albo klient anulował ją w aplikacji banku, zaproponuj ponowną rejestrację (krok 1) przy najbliższym kontakcie z klientem, np. przy odnowieniu subskrypcji.