Redirects and customer actions
Some payments cannot finish with a single API call. The customer has to do something first:
pass a 3-D Secure check, approve the payment in a banking or wallet app, or scan a QR code. When
that happens, VNSwitch returns the payment with status: "requires_customer_action" and a
next_action object that tells you what to show.
The pattern is always the same:
- Confirm the payment (or create it with
confirm: true). Include areturn_url. - If
statusisrequires_customer_action, readnext_action.typeand act on it. - The customer completes the step and, for redirects, comes back to your
return_url. - Your server checks the final status with VNSwitch before fulfilling the order.
Read the next action
next_action is only present while the payment is requires_customer_action. Branch on
next_action.type:
type | What to do | Fields |
|---|---|---|
redirect_to_url | Send the customer’s browser to the URL (full-page redirect, not an API call). Used for 3-D Secure and most bank and wallet pages. | redirect_to_url |
redirect_inside_popup | Open the URL in a pop-up window. | popup_url, redirect_response_url |
qr_code_information | Show the QR code for the customer to scan with their banking or wallet app. | image_data_url (a ready-to-use image), qr_code_url, raw_qr_data, display_text, display_to_timestamp |
fetch_qr_code_information | Fetch the QR code from the given URL and show it. | qr_code_fetch_url |
display_bank_transfer_information | Show the bank account details the customer must transfer to. | bank_transfer_steps_and_charges_details |
display_voucher_information | Show the voucher or payment slip the customer must pay. | voucher_details |
wait_screen_information | Show a “waiting for approval” screen while the customer approves in another app. | display_from_timestamp, display_to_timestamp |
collect_otp | Ask the customer for a one-time password. | consent_data_required |
A few other type values (third_party_sdk_session_token, invoke_sdk_client,
three_ds_invoke, invoke_hidden_iframe, invoke_ddc, invoke_upi_intent_sdk,
invoke_upi_qr_flow) are used only by specific payment providers. If your account uses one of
them, VNSwitch onboarding will tell you. If you receive a type you do not handle, show a generic
“could not complete payment” message and check the payment later; do not mark it as paid.
next_action for a redirect (3-D Secure, bank or wallet page)
{
"payment_id": "pay_8f2c1d9e0a",
"status": "requires_customer_action",
"next_action": {
"type": "redirect_to_url",
"redirect_to_url": "https://sandbox.api.vnswitch.nivc.ai/payments/redirect/pay_8f2c1d9e0a/merchant_demo/pay_8f2c1d9e0a_1"
}
}next_action for a QR code
{
"payment_id": "pay_8f2c1d9e0a",
"status": "requires_customer_action",
"next_action": {
"type": "qr_code_information",
"image_data_url": "data:image/png;base64,iVBORw0KGgo...",
"qr_code_url": "https://provider.example/qr/8f2c1d9e0a"
}
}Handle a redirect
When next_action.type is redirect_to_url, redirect the customer’s browser to
next_action.redirect_to_url, for example with an HTTP 302 from your server or
window.location.assign(url) in the browser. Do not fetch the URL from your server: the customer
has to see the page.
The customer then completes the step on the bank’s or provider’s page. VNSwitch receives the
result and sends the customer back to your return_url.
Set return_url on every payment that might need a redirect. If
you leave it out, VNSwitch uses the return URL set on your business profile. If neither is set,
the customer cannot be sent back.
Customer returns to your return_url
VNSwitch adds these query parameters to your return_url when it sends the customer back:
| Parameter | Description |
|---|---|
payment_id | The payment the customer just completed. |
status | The payment status at that moment, for example succeeded, requires_capture, processing or failed. |
payment_intent_client_secret | The payment’s client_secret. |
amount | The payment amount in the currency’s smallest unit. |
manual_retry_allowed | true if you can confirm the payment again after a failure. |
For example:
If your business profile has the payment response hash enabled, VNSwitch also adds signature
and signature_algorithm (HMAC-SHA512), signed with your payment response hash key. Your
business profile can also be set to send these values to your return_url as an HTTP POST
instead of query parameters; ask VNSwitch onboarding if you need that.
Treat the status in the URL as a hint for what to show the
customer, never as proof of payment. Anyone can edit a URL. Also avoid writing the full URL to logs
or analytics, because it contains the client_secret.
https://merchant.example.vn/checkout/return?status=succeeded&payment_id=pay_8f2c1d9e0a&payment_intent_client_secret=pay_8f2c1d9e0a_secret_Xk2pQ9rTz4&amount=150000&manual_retry_allowed=falseVerify the payment after the customer returns
When the customer lands on your return_url, take payment_id from the query string and
retrieve the payment from your server with your secret key. Add
force_sync=true so VNSwitch asks the provider for the latest status. Do not call
Confirm a payment again: the payment is already confirmed, and VNSwitch
rejects a second confirm while it waits for the customer.
Then act on the retrieved status:
succeeded(orrequires_capturewith manual capture): check thatamountandcurrencymatch your order, then fulfil it.processing: show “payment pending”. Wait for the webhook (see Webhooks).failed: show an error. Ifmanual_retry_allowedistrue, let the customer try again with Confirm a payment.requires_customer_action: the customer did not finish. Let them try again with the samenext_action, or cancel the payment.
The customer may also close the browser and never come back. Always rely on webhooks as well, so your order is updated even without a return. See Payment lifecycle.
Response
{
"payment_id": "pay_8f2c1d9e0a",
"status": "succeeded",
"amount": 150000,
"amount_received": 150000,
"currency": "VND",
"customer_id": "cus_demo_001",
"payment_method": "card",
"payment_method_type": "credit",
"next_action": null
}QR payments in Vietnam
Availability depends on the payment providers enabled for your account. Contact info@nivc.ai.
QR methods such as VietQR do not use a browser redirect in most cases. The customer scans a code
with their banking app and approves the transfer there. To start a VietQR payment, use
payment_method: "real_time_payment", payment_method_type: "viet_qr" and
payment_method_data: {"real_time_payment": {"viet_qr": {}}}:
Depending on the provider, next_action is:
qr_code_information: showimage_data_urlas an image (<img src="...">). Hide the code afterdisplay_to_timestampif it is set.fetch_qr_code_information: get the QR code fromqr_code_fetch_urland show it.redirect_to_url: some providers host the QR code on their own page. Redirect the customer to it as described in Handle a redirect.
While the QR code is on screen, the customer stays on your page, so there may be no return to
your return_url. Learn the result from the payment_succeeded or payment_failed webhook, or
retrieve the payment with force_sync=true every few seconds while the
code is shown. Stop polling when the status is final or the code expires.
{
"amount": 150000,
"currency": "VND",
"confirm": true,
"customer_id": "cus_demo_001",
"return_url": "https://merchant.example.vn/checkout/return",
"payment_method": "real_time_payment",
"payment_method_type": "viet_qr",
"payment_method_data": { "real_time_payment": { "viet_qr": {} } }
}