Skip to content

Payment Flow

The Paytalya integration is a two-step model:

  1. Server side (you): Create a payment request with POST /v1/payments (amount, terminal, returnUrl). The card is not part of this request. The response returns a paymentRef (a single-use payment reference) and a handoffUrl.
  2. Browser side (the buyer): Redirect the buyer’s browser/WebView, carrying the card and the paymentRef, to the handoffUrl (Paytalya’s separate handoff page, on the pay.* origin). The 3D Secure relay, the POST to the bank’s 3D page, and the callback all run on that page; once complete, the buyer returns to your returnUrl.

Hash generation, the bank’s 3D relay, callback handling, and capture happen on Paytalya’s side. You obtain the definitive result on the server side via GET /v1/payments and webhook.

  1. Create a payment request: send amount, terminalId, and returnUrl with POST /v1/payments (no card). The response returns paymentCode, status: initiated, paymentRef, and handoffUrl. See Create Payment.
  2. Hand off: redirect the buyer’s browser/WebView, carrying the card you collected plus the paymentRef, to the handoffUrl via a form POST. Detail: Card Handoff.
  3. 3D Secure: the handoff page starts the bank’s 3D relay; the buyer’s browser POSTs to the bank’s 3D Secure page and the buyer completes authentication. These steps run automatically on the handoff page; you do not build a form.
  4. Callback + capture: the bank reports the 3D result to Paytalya; Paytalya processes the callback and performs the capture.
  5. Return: the handoff page redirects the buyer’s browser/WebView to your returnUrl via 303. The result carried over returnUrl is not authoritative.
  6. Confirm the result: learn the definitive status via GET /v1/payments and webhook. Your decision (order confirmation, etc.) must always rely on this authoritative result.
server: POST /v1/payments (CARDLESS) ──► { paymentRef, handoffUrl, status: initiated }
browser/WebView: card + paymentRef ──POST──► [Paytalya handoff page (pay.*)]
│ (the handoff page POSTs to the bank's 3D)
[bank 3D Secure]
bank callback ──► [Paytalya: callback + capture]
303 (from the handoff page) ──► returnUrl (result NOT authoritative)
server: webhook + GET /v1/payments ──────────────► definitive status

The flow is the same on both channels; the only difference is how you create the browser context:

  • Web: the buyer’s native browser form-POSTs to the handoffUrl; on return the browser navigates to returnUrl via 303.
  • Mobile: the merchant app collects the card on its own native screen, opens a WebView, and POSTs the card plus the paymentRef to the handoffUrl. 3D completes inside the WebView; in the end the WebView lands on returnUrl.

Single attempt: one payment = one card attempt

Section titled “Single attempt: one payment = one card attempt”

3D can be started only once per paymentRef. If the buyer abandons or fails 3D, that payment becomes failed/expired and the paymentRef cannot be reused. To retry, create a new payment request (POST /v1/payments): the “retry = new payment” approach. Detail: Card Handoff.