Payment Flows
High-level map of create, confirm, requires_action, success, decline, capture, refund, cancel, and webhook flows in HSRC Pay.
This page provides a high-level map of HSRC Pay payment flows. Read it to enter the payment lifecycle, see the difference between Hosted Checkout and API-only integration, and move through sub-pages in the right order.
Payment integration is not only calling endpoints; it is state, provider behavior, risk, routing, and event discipline.
What is a payment flow?
In HSRC Pay, a payment flow starts when the merchant creates a Payment (CREATED), enters provider execution with Confirm, and reflects adapter results in Payment/Charge states.
Core model:
- Payment is created (
POST /v1/payments). - Payment Method is selected or collected inside Checkout Session.
- Confirm call starts execution (
POST /v1/payments/:id/confirm). - Routing plan orders provider candidates.
- For each candidate, a Charge is created and the provider adapter runs
pay. - Adapter result returns as
success,requires_action, orerror(includingdeclined). - Payment
statusand Chargestatusare updated. - Event/webhook is sent to the merchant system.
Core flow: create -> confirm -> result
| Stage | Responsibility | Note |
|---|---|---|
| Create | Prepares payment intent | status: CREATED, does not pull funds |
| Confirm | Starts provider execution | Response: data.payment + data.confirmResult |
| Result | Adapter + Payment/Charge status | Read confirmResult.latestResult.kind together with payment.status |
| Event/Webhook | Carries state change to backend | Critical for final verification |
const { data: created } = await api.post("/v1/payments", {
amount: 12500,
currency: "TRY",
auto_capture: true,
});
const { data } = await api.post(`/v1/payments/${created.payment.id}/confirm`, {
payment_method: { id: "pm_123" },
payer_identity: { ip_address: clientIp, user_agent: ua },
});
if (data.payment.status === "REQUIRES_ACTION" && data.confirmResult.paymentNextAction?.url) {
redirectUser(data.confirmResult.paymentNextAction.url);
}Hosted Checkout flow
Hosted Checkout manages the payment experience inside Checkout Session.
In this model the merchant:
- Creates a Checkout Session.
- Redirects the user with checkout URL/token.
- Leaves payment method collection and some 3DS/
REQUIRES_ACTIONsteps to the checkout experience. - Verifies the final result with webhook or
GET /v1/payments/:id.
Hosted Checkout is recommended for fast integration and a more controlled payment experience.
API-only flow
In the API-only model the merchant manages its own frontend and backend experience.
In this model the merchant:
- Manages Payment Method collection UI.
- Calls Confirm directly.
- Handles redirect/challenge when
REQUIRES_ACTIONandpaymentNextActionarrive. - Verifies final state after gateway 3DS callback via webhook or payment query.
API-only flow suits teams that want custom checkout, platform experience, or more UI control.
3DS / requires_action flow
Not every payment returns SUCCEEDED or AUTHORIZED immediately. With secure_mode or provider requirements, the adapter may return requires_action; Payment becomes REQUIRES_ACTION.
In this case:
- Confirm result may have
confirmResult.ok === trueandpayment.status === "REQUIRES_ACTION". - Merchant redirects the user with
confirmResult.paymentNextAction.url. - After challenge, the gateway processes resume via
three-d-secure-callback-urls/:id. - Final state is verified with event/webhook or payment GET.
Async and uncertain outcomes
Some provider behaviors may not produce an immediate terminal result. On timeout or uncertain status, the merchant should query the existing Payment (include_charges=true) idempotently instead of opening a new Payment.
There is no separate PENDING adapter kind on Payment; async waiting is usually managed with PROCESSING status or operational monitoring.
Webhook/event flow
Frontend or confirm response guides user experience; webhook closes merchant backend state.
Webhook handler should:
- Be idempotent
- Tolerate duplicate delivery
- Match records by Payment ID and trace/request id
- Interpret event types such as
payment.succeeded,payment.requires_action,payment.authorized,charge.declinedseparately
Capture / refund / cancel
| Operation | Condition | Effect |
|---|---|---|
| Capture | Payment AUTHORIZED, auto_capture: false | Charge capture, Payment SUCCEEDED |
| Refund | After successful collection | Refund record, Payment REFUNDED |
| Cancel | Payment AUTHORIZED | Authorization cancel, Payment CANCELED |
These operations appear in Payment context; financial effect is tracked at Charge level.
Error / decline behaviors
A successful payment integration is understood by handling decline, timeout, 3DS, and webhook behavior correctly, not only success responses.
- Decline: Charge
DECLINED, Payment usuallyREQUIRES_PAYMENT_METHOD(re-confirm can be planned). - Hard decline: Do not retry aggressively with the same card; ask for a different method or user action.
- Soft decline: Routing may try the next provider candidate (new charge attempt).
- Timeout: Check
GET /payments/:idand webhook logs before opening a new payment. - 3DS failed: Controlled retry after
REQUIRES_ACTIONorREQUIRES_PAYMENT_METHOD.
Related pages
- Confirm detail: Payment Lifecycle and Confirm
- Hosted checkout: Checkout Session Guide
- Payment/Charge domain split: Business Flow - Payments & Charges
- Decline tests: Testing Declines
- 3DS flow: 3DS Simulation