Przejdź do głównej zawartości

Apple Pay

Integracja Apple Pay pozwala klientom korzystającym z urządzeń Apple (iPhone, iPad, Mac z Touch ID/Face ID) na szybka płatność za pomoca kart zapisanych w Apple Wallet.

Schemat działania

Krok 1: Rejestracja płatności

Zarejestruj transakcję standardowo:

curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "transfers",
"service": "abc123",
"value": "79.99",
"url_success": "https://mojsklep.pl/sukces",
"url_fail": "https://mojsklep.pl/błąd",
"url_ipn": "https://mojsklep.pl/api/ipn",
"checksum": "..."
}'

Zapisz transactionId z odpowiedzi.

Krok 2: Inicjalizacja sesji Apple Pay

Gdy klient kliknie przycisk Apple Pay, przeglądarka wywołuje handler onvalidatemerchant z validationURL od Apple. W tym momencie Twoj serwer musi wywołać dpay.pl z xPayType: APPLE_PAY_INIT, aby otrzymać podpisaną sesje merchant:

POST https://api-payments.dpay.pl/api/v1_0/cards/payment/{transactionId}/pay/apple-pay
Content-Type: application/json

Zapytanie inicjalizacji sesji

{
"channelId": 31,
"xPayType": "APPLE_PAY_INIT",
"validationUrl": "https://apple-pay-gateway.apple.com/paymentservices/paymentSession",
"deviceInfo": {
"browserAcceptHeader": "application/json,text/plain,*/*",
"browserJavaEnabled": "false",
"browserLanguage": "pl-PL",
"browserColorDepth": 24,
"browserScreenHeight": 1080,
"browserScreenWidth": 1920,
"browserTZ": -60,
"browserUserAgent": "Mozilla/5.0 ...",
"systemFamily": "Win32",
"deviceID": "device-unique-id",
"applicationName": "Netscape"
}
}

Pola wymagane: channelId, xPayType, deviceInfo. channelId to identyfikator kanału kartowego przekazany przez BOK dpay.

Odpowiedz

dpay.pl zwraca sesje merchant zakodowaną w Base64 w polu redirectText. Po zdekodowaniu otrzymujesz gotowy obiekt ApplePayMerchantSession, który należy przekazać do session.completeMerchantValidation().

{
"success": true,
"status": "success",
"message": {
"redirectText": "<Base64(JSON ApplePayMerchantSession)>",
"redirectType": "FORM"
}
}

Zdekodowany redirectText zawiera:

{
"epochTimestamp": 1700000000,
"expiresAt": 1700003600,
"merchantSessionIdentifier": "SSH...",
"nonce": "abc123",
"merchantIdentifier": "merchant.pl.dpay",
"domainName": "mojsklep.pl",
"displayName": "dpay.pl",
"signature": "..."
}

Krok 3: Konfiguracja przycisku Apple Pay

<!-- Sprawdz dostępnosc Apple Pay -->
<div id="apple-pay-button" style="display: none;"></div>

<style>
#apple-pay-button {
-webkit-appearance: -apple-pay-button;
-apple-pay-button-type: pay;
-apple-pay-button-style: black;
width: 100%;
height: 48px;
cursor: pointer;
}
</style>

JavaScript - pełna integracja

// Sprawdz, czy Apple Pay jest dostępny
if (window.ApplePaySession && ApplePaySession.canMakePayments()) {
document.getElementById('apple-pay-button').style.display = 'block';
}

document.getElementById('apple-pay-button').addEventListener('click', async () => {
const transactionId = '...'; // Z Kroku 1

// Konfiguracja zadania płatności
const paymentRequest = {
countryCode: 'PL',
currencyCode: 'PLN',
supportedNetworks: ['visa', 'masterCard'],
merchantCapabilities: ['supports3DS'],
total: {
label: 'Moj Sklep',
amount: '79.99',
},
};

const session = new ApplePaySession(3, paymentRequest);

// Walidacja sesji - wymagane przez Apple
session.onvalidatemerchant = async (event) => {
try {
const response = await fetch('/api/pay/apple-pay/session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
transactionId,
validationUrl: event.validationURL,
}),
});

const result = await response.json();

if (!result.success) {
throw new Error(result.message);
}

// dpay zwraca sesje w redirectText zakodowaną w Base64
const merchantSession = JSON.parse(atob(result.message.redirectText));
session.completeMerchantValidation(merchantSession);
} catch (error) {
session.abort();
console.error('Błąd walidacji sesji:', error);
}
};

// Obsługa autoryzacji płatności
session.onpaymentauthorized = async (event) => {
try {
// Cały obiekt tokena (event.payment.token) serializujemy do JSON
// i kodujemy w Base64 przed wysłaniem do dpay.pl
const xPayToken = btoa(JSON.stringify(event.payment.token));
const email = event.payment.billingContact?.emailAddress
|| event.payment.shippingContact?.emailAddress;

const response = await fetch('/api/pay/apple-pay/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
transactionId,
email,
xPayToken,
}),
});

const result = await response.json();

if (result.success) {
// Dla Apple Pay odpowiedz to zawsze redirectType: 'SUCCESS' albo błąd.
// Autoryzacja (w tym 3DS) odbywa się w portfelu Apple Pay po stronie klienta.
session.completePayment(ApplePaySession.STATUS_SUCCESS);
window.location.href = '/sukces';
} else {
session.completePayment(ApplePaySession.STATUS_FAILURE);
}
} catch (error) {
session.completePayment(ApplePaySession.STATUS_FAILURE);
}
};

session.oncancel = () => {
console.log('Klient anulował płatność Apple Pay');
};

// Rozpocznij sesje
session.begin();
});

Serwer - obsługa endpointow

Oba wywołania trafiają na ten sam endpoint dpay (/pay/apple-pay) - różnią się wyłącznie wartością xPayType.

Inicjalizacja sesji (APPLE_PAY_INIT)

app.post('/api/pay/apple-pay/session', async (req, res) => {
const { transactionId, validationUrl } = req.body;

const response = await axios.post(
`https://api-payments.dpay.pl/api/v1_0/cards/payment/${transactionId}/pay/apple-pay`,
{
channelId: process.env.DPAY_CARD_CHANNEL_ID,
xPayType: 'APPLE_PAY_INIT',
validationUrl,
deviceInfo: buildDeviceInfo(req),
}
);

res.json(response.data);
});

Przetwarzanie płatności (APPLE_PAY)

app.post('/api/pay/apple-pay/process', async (req, res) => {
const { transactionId, email, xPayToken } = req.body;

const response = await axios.post(
`https://api-payments.dpay.pl/api/v1_0/cards/payment/${transactionId}/pay/apple-pay`,
{
email,
channelId: process.env.DPAY_CARD_CHANNEL_ID,
xPayType: 'APPLE_PAY',
xPayToken, // Base64(JSON.stringify(event.payment.token))
deviceInfo: buildDeviceInfo(req),
}
);

res.json(response.data);
});

function buildDeviceInfo(req) {
return {
browserAcceptHeader: req.headers['accept'] || 'application/json',
browserJavaEnabled: 'false',
browserLanguage: req.headers['accept-language']?.split(',')[0] || 'pl-PL',
browserColorDepth: 24,
browserScreenHeight: 1080,
browserScreenWidth: 1920,
browserTZ: 0,
browserUserAgent: req.headers['user-agent'] || 'Unknown',
systemFamily: 'Unknown',
deviceID: req.ip || 'unknown',
applicationName: 'Netscape',
};
}

Odpowiedzi API

Każde wywołanie (zarowno INIT, jak i płatność) zwraca strukture {success, status, message}. Dla sukcesu message jest obiektem {redirectText, redirectType}, dla błędu - komunikatem tekstowym.

3D Secure

W Apple Pay autoryzacja (w tym ewentualne 3DS) odbywa się w portfelu Apple Pay po stronie klienta, zanim token zostanie wysłany do dpay. Endpoint płatności (xPayType: APPLE_PAY) zwraca zawsze redirectType: "SUCCESS" dla udanej transakcji albo błąd - nigdy nie zwraca FORM z wyzwaniem 3DS. Typ FORM występuje wyłącznie w odpowiedzi na APPLE_PAY_INIT i zawiera wtedy zakodowaną w Base64 sesje merchant.

Sukces płatności

{
"success": true,
"status": "success",
"message": {
"redirectText": "",
"redirectType": "SUCCESS"
}
}

Błąd

{
"success": false,
"status": "error",
"message": "Error during payment creation"
}

Testowanie w trybie sandbox

W trybie testowym nie musisz wywoływać prawdziwego Apple Pay sheet. Zamiast tokena z portfela przekaż specjalną wartość testową w polu xPayToken:

TokenScenariusz
TEST_SUCCESSPłatność zakończona sukcesem
TEST_SUCCESS_DELAYEDSukces po dłuższym oczekiwaniu
TEST_DECLINETransakcja odrzucona
TEST_INSUFFICIENTBrak środków
TEST_TIMEOUTTimeout
TEST_ERRORBłąd systemu

Przykład testowego zapytania (krok 3 - bez kroków 1-2):

curl -X POST https://api-payments.dpay.pl/api/v1_0/cards/payment/{transactionId}/pay/apple-pay \
-H "Content-Type: application/json" \
-d '{
"channelId": 31,
"xPayType": "APPLE_PAY",
"xPayToken": "TEST_SUCCESS",
"deviceInfo": {
"browserAcceptHeader": "application/json",
"browserJavaEnabled": "false",
"browserLanguage": "pl-PL",
"browserColorDepth": 24,
"browserScreenHeight": 1080,
"browserScreenWidth": 1920,
"browserTZ": 0,
"browserUserAgent": "Mozilla/5.0",
"systemFamily": "Darwin",
"deviceID": "test-device",
"applicationName": "Netscape"
}
}'

Pełna lista tokenów testowych na stronie Środowisko testowe.

Wymagania

Konfiguracja Apple Pay
  • Twoja domena musi byc zweryfikowana w Apple - dpay.pl obsługuje walidacje domeny w ramach procesu APPLE_PAY_INIT
  • Strona musi byc dostępna przez HTTPS
  • Apple Pay działa wyłącznie na urządzeniach Apple z Safari (lub Chrome na iOS 16+)
  • Nie jest możliwe testowanie Apple Pay na urządzeniach z systemem Android lub Windows