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
jwtz pola karty albo ze zdarzeniacompleteportfela. 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ętajdata.id. Klienta nie przekierowujesz naredirectUrl; 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 dlatokenType: 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
}
}'
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
tokenType | string | tak | Ską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. |
token | string | tak | Wartość jwt zwrócona przez SDK. Maksymalnie 5000 znaków. |
cardHolder | string | dla SDK_CARD | Imię i nazwisko posiadacza karty, do 64 znaków. |
browser | object | tak | Dane 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:
| Pole | Opis |
|---|---|
actionId | Identyfikator tej próby płatności (ULID). |
status | Status próby płatności: CREATED, PENDING, PAID, SETTLED, FAILED lub CANCELED. To nie jest status transakcji. |
nextAction | Co 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 HTTP | errors[].code | Znaczenie |
|---|---|---|
400 | TRANSACTION_CARD_PROCESSING_ERROR | Płatność odrzucona. details.cardErrorCode podaje powód, np. CARD_INSUFFICIENT_FUNDS; listę kodów znajdziesz przy kwotach testowych. |
400 | TRANSACTION_INVALID_STATUS | Transakcja nie jest w statusie pozwalającym na płatność, np. jest już opłacona albo wygasła. |
400 | TRANSACTION_MISSING_DATA | Transakcji brakuje danych wymaganych do płatności kartą; details.field wskazuje pole. |
400 | PROVIDER_NOT_SUPPORTED | Punkt płatności nie ma włączonych płatności kartą przez SDK. |
404 | TRANSACTION_NOT_FOUND, POINT_NOT_FOUND | Zły transactionId albo pointId. |
422 | VALIDATION_ERROR | Niepoprawne body, np. brak pola w browser albo token po terminie. |
429 | TOO_MANY_PAYMENT_ATTEMPTS | Za dużo prób płatności dla tej transakcji. Utwórz nową transakcję. |
Pełna referencja: Process card transaction.
Co dalej
- Testowanie i wdrożenie: karty wymuszające challenge, odrzucenia i błędy.
- Zmiana statusu transakcji (webhook)