Przejdź do głównej zawartości

Zrealizuj płatność tokenem

Na tej stronie Twój backend zamieni token z Card SDK na płatność: wyśle go do Payment API, obsłuży ewentualny challenge 3-D Secure i odbierze końcowy status.

Wymagania

  • Token jwt z pola karty albo ze zdarzenia complete portfela. Token jest ważny 60 sekund i można go użyć raz.
  • Utworzona transakcja. Token realizuje płatność dla istniejącej transakcji, więc najpierw wywołaj POST /v1_2/payment/points/{pointId}/transactions (zob. Tworzenie transakcji) i zapamiętaj data.id. Klienta nie przekierowujesz na redirectUrl; zostaje w Twoim checkoucie.
  • Obsłużony webhook PAYMENT.TRANSACTION_STATUS_CHANGED, bo to on niesie ostateczny wynik płatności.

Jak to działa

Krok 1. Zbierz dane w przeglądarce

Razem z tokenem wyślij do backendu dane, których wymaga endpoint:

  • imię i nazwisko posiadacza karty (cardHolder), wymagane dla tokenType: SDK_CARD. Pole karty ich nie zbiera, więc dodaj własny input w checkoucie;
  • dane przeglądarki (browser), wymagane zawsze. Bank używa ich w 3-D Secure, żeby ocenić, czy potrzebny jest challenge:
const browser = {
userAgent: navigator.userAgent,
language: navigator.language, // np. "pl-PL"
colorDepth: screen.colorDepth, // 1, 4, 8, 15, 16, 24, 30, 32 lub 48
screenWidth: screen.width,
screenHeight: screen.height,
timezoneOffset: new Date().getTimezoneOffset(), // minuty, np. -120
javaEnabled: false,
javascriptEnabled: true,
};

await fetch('/api/checkout/pay', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ transactionId, token: result.jwt, cardHolder, browser }),
});

Zrób to od razu po tokenizacji. Nigdy nie umieszczaj tokenu w URL-u ani w logach.

Krok 2. Wyślij token do Payment API

curl -X POST "https://api.sandbox.paymentic.com/v1_2/payment/points/{pointId}/transactions/{transactionId}/cards" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tokenType": "SDK_CARD",
"token": "eyJhbGciOiJFUzI1NiJ9...",
"cardHolder": "Jan Kowalski",
"browser": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"language": "pl-PL",
"colorDepth": 24,
"screenWidth": 1920,
"screenHeight": 1080,
"timezoneOffset": -120,
"javaEnabled": false,
"javascriptEnabled": true
}
}'
PoleTypWymaganeOpis
tokenTypestringtakSkąd pochodzi token: SDK_CARD (pole karty), SDK_GOOGLE_PAY, SDK_APPLE_PAY (portfele przez Card SDK). Wartości GOOGLE_PAY i APPLE_PAY są dla tokenów portfeli uzyskanych bez Card SDK.
tokenstringtakWartość jwt zwrócona przez SDK. Maksymalnie 5000 znaków.
cardHolderstringdla SDK_CARDImię i nazwisko posiadacza karty, do 64 znaków.
browserobjecttakDane przeglądarki płatnika z kroku 1. Wszystkie osiem pól jest wymaganych.

Krok 3. Obsłuż odpowiedź

Odpowiedź ma ten sam kształt dla obu przypadków:

PoleOpis
actionIdIdentyfikator tej próby płatności (ULID).
statusStatus próby płatności: CREATED, PENDING, PAID, SETTLED, FAILED lub CANCELED. To nie jest status transakcji.
nextActionCo musi jeszcze zrobić płatnik. null, gdy nic. Pola: type, method, url, form, contentType, raw.

200 OK: bez udziału płatnika

Płatność została rozliczona od razu, nextAction jest null. Na ostateczny status transakcji i tak czekaj w webhooku; dopiero PAID na transakcji oznacza otrzymanie środków.

202 Accepted: challenge 3-D Secure

Bank wymaga potwierdzenia od płatnika. W nextAction dostajesz stronę challenge'u:

{
"data": {
"actionId": "01kaqf5trc82bk6cqqanjcjwnq",
"status": "PENDING",
"nextAction": {
"type": "3DS_SDK",
"method": "POST",
"url": "https://challenge.paymentic.com/01kaqf5trc82bk6cqqanjcjwnq",
"form": null,
"contentType": null,
"raw": null
}
}
}

Zwróć nextAction do przeglądarki i otwórz płatnikowi nextAction.url w iframe osadzonym w checkoucie. Jeśli Twoja strona wysyła CSP, host challenge.paymentic.com musi być w frame-src; zob. Content Security Policy. Gdy form nie jest null, wyślij jego pola metodą z method na url. Po potwierdzeniu u banku wynik przychodzi webhookiem.

Krok 4. Odbierz wynik

Ostateczny wynik niesie webhook PAYMENT.TRANSACTION_STATUS_CHANGED: PAID oznacza otrzymanie środków, FAILED odrzucenie (także po nieudanym challenge'u). Jeśli webhook nie dotrze, odpytaj GET /v1_2/payment/points/{pointId}/transactions/{transactionId}; zob. Statusy transakcji.

Po odrzuceniu pozwól klientowi spróbować ponownie: tokenizuj kartę jeszcze raz (token jest jednorazowy) i wyślij nowy token dla tej samej transakcji.

Błędy

Kod HTTPerrors[].codeZnaczenie
400TRANSACTION_CARD_PROCESSING_ERRORPłatność odrzucona. details.cardErrorCode podaje powód, np. CARD_INSUFFICIENT_FUNDS; listę kodów znajdziesz przy kwotach testowych.
400TRANSACTION_INVALID_STATUSTransakcja nie jest w statusie pozwalającym na płatność, np. jest już opłacona albo wygasła.
400TRANSACTION_MISSING_DATATransakcji brakuje danych wymaganych do płatności kartą; details.field wskazuje pole.
400PROVIDER_NOT_SUPPORTEDPunkt płatności nie ma włączonych płatności kartą przez SDK.
404TRANSACTION_NOT_FOUND, POINT_NOT_FOUNDZły transactionId albo pointId.
422VALIDATION_ERRORNiepoprawne body, np. brak pola w browser albo token po terminie.
429TOO_MANY_PAYMENT_ATTEMPTSZa dużo prób płatności dla tej transakcji. Utwórz nową transakcję.

Pełna referencja: Process card transaction.

Co dalej