PHP SDK
✅ Dostępne - wersja 0.1.1
Oficjalna biblioteka PHP do integracji z API dpay.pl. Automatyzuje generowanie sum kontrolnych, weryfikację powiadomień IPN oraz wywołania API: rejestrację płatności, szczegóły transakcji, zwroty, listę banków, aliasy BLIK, płatności kartowe server-to-server i wypłaty 1:1. Kwoty są reprezentowane obiektem Money (grosze jako int), a odpowiedzi API mapowane na typowane obiekty.
Wymagania
- PHP 7.4 lub nowszy (testowane do PHP 8.5)
- Rozszerzenia:
curl,json,openssl - Composer
Biblioteka nie ma żadnych zależności runtime poza rozszerzeniami PHP.
Instalacja
composer require dpayglobal/dpay-php-sdk
Pakiet jest publikowany na Packagist, a kod źródłowy dostępny na GitHub.
Konfiguracja
Utwórz instancję klienta DPay\DPayClient, podając dane z Panelu dpay.pl:
use DPay\DPayClient;
$dpay = new DPayClient([
'service' => 'nazwa_serwisu',
'secret_hash' => 'twoj_secret_hash',
]);
| Opcja | Typ | Opis |
|---|---|---|
service | string | Nazwa serwisu (Punktu Płatności) z panel.dpay.pl (wymagane) |
secret_hash | string | Klucz Hash (Secret Hash) do generowania sum kontrolnych (wymagane) |
timeout | int | Timeout żądań HTTP w sekundach (domyślnie 30) |
http_client | HttpClientInterface | Własny klient HTTP (testy, proxy) |
base_urls | array | Nadpisanie hostów API (klucze: api_payments, panel, gateway) |
Klient udostępnia serwisy jako publiczne właściwości:
| Serwis | Zakres |
|---|---|
$dpay->payments | Rejestracja płatności, szczegóły transakcji |
$dpay->refunds | Zwroty i sprawdzanie dostępności zwrotu |
$dpay->banks | Lista banków pay-by-link |
$dpay->blik | Aliasy BLIK OneClick i Recurring |
$dpay->cards | Płatności kartowe server-to-server |
$dpay->payouts | Szczegóły wypłat 1:1 |
Kwoty - obiekt Money
Wszystkie kwoty w SDK to obiekt DPay\Money, wewnętrznie przechowujący grosze jako int. SDK sam dba o właściwy format kwoty dla każdego endpointu (kwota dziesiętna albo grosze), więc nie musisz pamiętać, który endpoint oczekuje którego formatu.
use DPay\Money;
Money::pln(1050); // 10.50 PLN
Money::of(500, 'EUR'); // 5.00 EUR
Money::fromDecimal('10.50', 'PLN');
$money->getMinor(); // 1050 (grosze)
$money->toDecimal(); // "10.50"
Rejestracja płatności
Żądanie budujesz obiektem RegisterPaymentRequest - pola wymagane w create(), opcjonalne przez settery with*(). Suma kontrolna i pole transactionType są dokładane automatycznie:
use DPay\DPayClient;
use DPay\Money;
use DPay\Payment\Payer;
use DPay\Payment\RegisterPaymentRequest;
use DPay\Payment\ReturnUrls;
use DPay\Payment\TransactionType;
$dpay = new DPayClient([
'service' => 'nazwa_serwisu',
'secret_hash' => 'twoj_secret_hash',
]);
$payment = $dpay->payments->register(
RegisterPaymentRequest::create(
Money::pln(1050),
TransactionType::TRANSFERS,
new ReturnUrls(
'https://twojsklep.pl/sukces',
'https://twojsklep.pl/blad',
'https://twojsklep.pl/ipn'
)
)
->withDescription('Zamówienie #1234')
->withCustom('order-1234')
->withPayer(Payer::create()->withEmail('klient@example.com'))
);
if ($payment->getRedirectUrl() !== null) {
header('Location: ' . $payment->getRedirectUrl());
exit;
}
if ($payment->isPaid()) {
// płatność rozliczona inline (np. BLIK Level 0)
}
Typy transakcji (TransactionType): TRANSFERS, DCB_GATEWAY, CARD_AUTH, MB_WAY_DIRECT, BIZUM_DIRECT, BLIK_RECURRING, CARD_RECURRING.
Ważniejsze settery RegisterPaymentRequest
| Metoda | Opis |
|---|---|
withDescription(string) | Opis transakcji widoczny dla klienta |
withCustom(string) | Własne dane identyfikujące zamówienie (wracają w IPN) |
withPayer(Payer) | E-mail oraz imię i nazwisko klienta |
withChannel(string) | Płatność bezpośrednia wskazanym kanałem banku |
withCreditCard(bool) / withPaypal(bool) / withPaysafecard(bool) / withInstallment(bool) / withBlik(bool) | Włączenie lub wyłączenie metod na bramce |
withNoBanks(bool) | Ukrycie listy banków |
withBlikCode(string $code, string $userAgent, string $userIp) | Płatność BLIK Level 0 (kod 6-cyfrowy) |
withBlikAlias(string $alias, string $userAgent, string $userIp) | Płatność aliasem BLIK OneClick |
withRegisterBlikAlias(BlikAliasRegistration) | Rejestracja aliasu OneClick przy płatności |
withCardRecurring(CardRecurringRegistration) | Rejestracja mandatu card recurring |
withCardRecurringAlias(string) | Obciążenie zapisanej karty (MIT) |
withPayout(PayoutInstruction) | Instrukcja wypłaty 1:1 |
withEfaktura(?InvoiceDetails) | Płatność za eFakturę (KSeF) |
withPhoneNumber(string $phone, string $currency) | MB WAY |
Obsługa IPN
Powiadomienia IPN weryfikujesz przez IpnVerifier::constructEvent() - nieprawidłowy podpis rzuca SignatureVerificationException:
use DPay\Exception\SignatureVerificationException;
use DPay\Ipn\IpnEvent;
use DPay\Ipn\IpnVerifier;
try {
$event = IpnVerifier::constructEvent(
(string) file_get_contents('php://input'),
'twoj_secret_hash'
);
if ($event->isTransfer()) {
markOrderAsPaid($event->getId(), $event->getAmount());
}
if ($event->isCapture()) {
markOrderAsCaptured($event->getId(), $event->getAmount(), $event->getCapturePaymentId());
}
http_response_code(200);
echo IpnEvent::ACK;
} catch (SignatureVerificationException $e) {
http_response_code(400);
echo 'Invalid signature';
}
OKdpay.pl uznaje IPN za dostarczony wyłącznie, gdy treść odpowiedzi to dokładnie OK (stała IpnEvent::ACK). Kod HTTP nie jest sprawdzany. Upewnij się, że framework nie dokleja niczego do body.
Zawsze porównaj $event->getAmount() (string, np. "10.00") z kwotą zamówienia w Twojej bazie i przetwarzaj każdą transakcję tylko raz (IPN może przyjść wielokrotnie).
Szczegóły transakcji
$transaction = $dpay->payments->details('identyfikator-transakcji');
$transaction->getStatus(); // 'paid', 'created', 'processing', 'expired', 'captured'
$transaction->isPaid(); // true dla paid i captured
$transaction->getValue()->toDecimal(); // "29.99"
$transaction->getRefundedAmount(); // Money
$transaction->getAvailableRefundAmount(); // Money
$transaction->isFullyRefunded(); // bool
$transaction->getRefunds(); // TransactionRefund[]
Zwroty
use DPay\Money;
// zwrot pełny
$refund = $dpay->refunds->create('identyfikator-transakcji');
// zwrot częściowy z powodem
$refund = $dpay->refunds->create('identyfikator-transakcji', Money::pln(500), 'reklamacja');
$refund->isAccepted();
Przed zwrotem możesz sprawdzić jego dostępność - metoda zwraca wynik biznesowy (nie rzuca wyjątku), także gdy zwrot jest niemożliwy:
$availability = $dpay->refunds->checkAvailability('identyfikator-transakcji', Money::pln(500));
if (!$availability->isAvailable()) {
$availability->getMessage(); // np. "Transakcja nie została opłacona"
$availability->getHttpStatus(); // stabilny kod przyczyny, patrz tabela
}
| Kod HTTP | Przyczyna odmowy |
|---|---|
400 | Kwota przekracza dostępną kwotę zwrotu |
401 | Kanał płatności nie obsługuje zwrotów |
402 | Transakcja nie została opłacona |
406 | Niewystarczające saldo na pokrycie zwrotu |
409 | Wniosek o zwrot został już złożony |
410 | Transakcja została już zwrócona |
411 | Transakcje obciążeniowe nie podlegają zwrotom |
Banki
$banks = $dpay->banks->all(); // wszystkie banki dpay.pl
$banks = $dpay->banks->forService(); // banki dostępne dla Twojego serwisu
$banks[0]->getId();
$banks[0]->getName();
BLIK - aliasy OneClick i Recurring
$alias = $dpay->blik->alias('DPAY.UID.123456.abc12345');
$alias->isActive();
$alias->getApps();
$dpay->blik->unregisterAlias('DPAY.UID.123456.abc12345');
$status = $dpay->blik->recurringStatus('PAYID-...');
$status->getRegistration();
Rejestracja aliasu i płatność aliasem odbywają się przez rejestrację płatności (withBlikCode + withRegisterBlikAlias, płatność przez withBlikAlias).
Karty server-to-server
Dane karty szyfrujesz kluczem RSA pobieranym przed każdą próbą płatności:
use DPay\Card\CardData;
use DPay\Card\CardEncryptor;
use DPay\Card\CardPaymentRequest;
use DPay\Card\DccDecision;
use DPay\Payment\DeviceInfo;
$publicKey = $dpay->cards->publicKey();
$encrypted = (new CardEncryptor())->encrypt(
new CardData('4111111111111111', '123', '12/30'),
$transactionId,
$publicKey
);
$deviceInfo = DeviceInfo::create(/* dane przeglądarki płatnika */);
$result = $dpay->cards->payOtp($transactionId, CardPaymentRequest::create($deviceInfo)
->withEncryptedCardData($encrypted)
->withCardHolder('Jan', 'Kowalski')
->withChannelId(31));
if ($result->isSuccess()) {
// płatność przechwycona
} elseif ($result->requiresThreeDsForm()) {
$html = $result->getThreeDsFormHtml(); // wyrenderuj w przeglądarce płatnika
} elseif ($result->hasDccOffer()) {
$offer = $result->getDccOffer(); // pokaż ofertę DCC płatnikowi
// decyzję odeślij ponownym payOtp z ->withDccDecision(DccDecision::ACCEPT)
}
Dostępne są także: preAuth() (pre-autoryzacja), capture() i cancel() (przechwycenie i anulowanie), googlePay() oraz applePay(). Odrzucenie płatności przy HTTP 200 rzuca CardPaymentException z kodem błędu.
Karty S2S wymagają zgodności PCI-DSS po stronie merchanta. Szczegóły przepływu znajdziesz w dokumentacji kart S2S.
Wypłaty 1:1
$details = $dpay->payouts->details(12345);
$details->isProcessed();
$details->getNet()->toDecimal();
$details->getReceiver();
Obsługa błędów
Wszystkie wyjątki SDK implementują DPay\Exception\ExceptionInterface:
| Wyjątek | Kiedy |
|---|---|
TransportException | Błąd sieci - status płatności nieznany, użyj payments->details() |
AuthenticationException | 401 - błędny checksum lub secret hash |
InvalidRequestException | 400/422 - błędy walidacji (getFieldErrors()) |
NotFoundException | 404 - zasób nie istnieje |
RateLimitException | 429 - limit żądań (getRetryAfter()) |
PaymentRejectedException | Rejestracja odrzucona (np. błędny kod BLIK; getTransactionId()) |
CardPaymentException | Odrzucenie płatności kartowej (getErrorCode()) |
SignatureVerificationException | Nieprawidłowy podpis IPN |
ApiServerException | 5xx lub niepoprawna odpowiedź API |
use DPay\Exception\ApiErrorException;
use DPay\Exception\InvalidRequestException;
use DPay\Exception\TransportException;
try {
$payment = $dpay->payments->register($request);
} catch (InvalidRequestException $e) {
$e->getFieldErrors(); // array<string, string[]>
} catch (ApiErrorException $e) {
$e->getHttpStatus();
$e->getErrorCode();
} catch (TransportException $e) {
// nie wiadomo, czy żądanie dotarło - zweryfikuj przez payments->details()
}