A payment gateway is a hosted transaction system that securely collects payment after a merchant creates a payment request and redirects the user into a gateway-controlled payment page.
The gateway frontend is responsible for:
- loading payment session context
- rendering payment methods
- collecting payment input
- handling payment state
- returning final transaction result
Because payment involves external providers and banks, the frontend must handle both immediate user interaction and delayed transaction state safely.
R — Requirements
Functional Requirements
Core Payment Flow
The gateway should support:
- session-based entry
- payment method selection
- payment submission
- authentication flow
- final status display
- retry when allowed
Payment Methods
The gateway should support:
- card
- UPI
- wallet
- net banking
Payment State Handling
The UI should clearly represent:
- processing
- success
- failed
- pending
Non-Functional Requirements
Security
Sensitive payment input must remain isolated.
Reliability
Duplicate payment attempts should be prevented.
Performance
Payment UI should load quickly after redirect.
Accessibility
Payment controls should remain keyboard accessible.
A — Architecture
At architecture level, a hosted payment gateway usually exposes a JavaScript SDK so merchants do not directly handle sensitive payment details.
Instead of sending raw card data to the merchant backend, the browser loads the gateway SDK, tokenizes payment data inside the browser, and submits only a secure token for transaction execution.
This reduces merchant security burden and keeps sensitive payment data inside gateway-controlled boundaries.
End-to-End Payment Flow
A typical hosted payment flow with SDK-based tokenization works in two stages:
- merchant creates payment session
- gateway frontend executes payment using browser SDK
Complete Payment Flow
User clicks Pay
│
▼
Merchant Frontend
│
│ POST /create-payment
▼
Merchant Backend
│
│ create paymentIntent + session
▼
Payment Gateway Backend
│
│ returns redirectUrl + sdk config
▼
Browser redirects
▼
Gateway Frontend (/session/:sessionId)
│
│ fetch session
▼
Load Payment SDK
│
│ tokenize payment data
▼
Gateway Backend
│
│ confirm payment using token
▼
Payment Provider / Bank
│
▼
Gateway Frontend Final StateWhy JavaScript SDK Is Used
Sensitive payment details such as card number, CVV, and expiry should not pass through merchant-controlled systems.
The gateway SDK isolates this by handling sensitive input directly in the browser.
The merchant or gateway UI only interacts with secure SDK components.
Typical responsibilities of the SDK:
- render secure payment fields
- validate payment input
- tokenize sensitive data
- return secure payment token
This ensures raw payment data never becomes part of normal application state.
SDK Initialization
Once the gateway frontend loads session data, it initializes the SDK using session-bound configuration.
Example
const sdk = Gateway.init({
sessionId: "sess_7890"
});The SDK now knows which active transaction it belongs to.
This binding is important because tokenization must remain tied to one valid payment session.
Secure Field Rendering
The SDK usually injects secure hosted fields into the payment page.
Instead of normal input fields, secure fields are controlled by the gateway.
Examples:
- card number
- expiry
- CVV
This allows the gateway to isolate sensitive data from surrounding frontend logic.
Tokenization in Browser
When the user submits payment details, the SDK converts raw input into a payment token.
Example
const token = await sdk.tokenize();The returned token represents payment data safely.
Example token:
tok_x9ab23At this point raw payment details are discarded.
The frontend never stores card details after token generation.
Payment Confirmation Using Token
The gateway frontend sends only the token and payment intent reference to backend.
Example
POST /payments/pi_10234/confirm
{
token: "tok_x9ab23"
}The backend uses this token to complete payment with provider systems.
This separation ensures backend never receives raw payment fields directly from UI.
Authentication Step
Some payment methods require additional verification after tokenization.
Typical examples:
- OTP
- bank challenge
- redirect-based verification
The SDK or gateway frontend moves into authentication state before final payment completion.
Final Transaction Resolution
After provider processing completes, frontend queries current transaction status.
Possible final states:
- success
- failed
- pending
The UI should always reflect backend-confirmed payment state.
SSR vs CSR vs SSG
Chosen: CSR
Area | Rendering Strategy | Why |
|---|---|---|
Checkout interaction | CSR | Requires browser-side payment SDK execution |
Payment status page | CSR | Depends on live transaction state |
Confirmation page | SSR (optional) | Useful after payment completes |
Payment systems are interaction-heavy.
Checkout requires:
- provider SDK loading
- secure iframe rendering
- browser event handling
These are browser-native behaviors.
Server rendering adds little value during active payment execution.
That makes CSR the primary rendering model.
SPA vs MPA
Chosen: SPA
Payment flows benefit from single-page continuity.
SPA allows:
- preserve transaction state
- avoid full reload during payment step transitions
- maintain provider SDK lifecycle
This is important because payment state must remain stable during:
- retries
- intermediate authentication
- delayed responses
MPA introduces full navigation boundaries which increase state recovery complexity.
For critical checkout flows, SPA gives smoother control.
REST vs GraphQL
Chosen: REST
Payment systems typically use REST because transaction operations are strongly action-oriented.
Examples:
- create payment intent
- fetch payment status
- confirm transaction
These operations map naturally to explicit endpoints.
REST also simplifies:
- idempotency enforcement
- backend observability
- provider interoperability
GraphQL is less common because payments usually require strict endpoint semantics rather than flexible query composition.
Transport Protocol Choice
Chosen: HTTP/2
Payment systems benefit strongly from HTTP/2 because checkout often loads:
- payment SDK
- provider assets
- transaction APIs
HTTP/2 improves:
- multiplexing
- header compression
- parallel resource delivery
Compared to HTTP/1.1:
This reduces latency during checkout initialization.
HTTP/3 may help further on unstable mobile networks, but HTTP/2 remains standard for most payment stacks.
Communication Protocols
Payment systems are mostly request-driven, but some transaction visibility requires controlled realtime updates.
Primary Flow: HTTP
Used for:
- create payment
- confirm payment
- fetch final status
This remains the core transport.
Delayed Confirmation: Short Polling
Chosen for browser-side status visibility
After payment submission, frontend may periodically request latest status:
GET /payments/:id/statusWhy polling is required:
Because backend webhook updates are invisible directly to browser.
Polling allows frontend to detect delayed final confirmation safely.