Real-time payments
Instant account-to-account rails: the customer approves in an app or scans a QR, the money moves in seconds, and confirmation is final. This page walks the two highest-volume rails — UPI and PIX — end to end, then covers the rest of the family.
The real-time methods
| Method | payment_method | Region | Customer experience |
|---|---|---|---|
| UPI | upi | India | Collect request to a VPA, or scan-to-pay QR; approve with UPI PIN |
| PIX | pix | Brazil | Dynamic QR / copy-paste Pix code in any bank app |
| BLIK | blik | Poland | 6-digit code from the bank app, then in-app confirm |
| Swish | swish | Sweden | Phone number + approval in the Swish app |
| MB WAY | mb_way | Portugal | Phone number + approval in the MB WAY app |
| PayNow | paynow | Singapore | QR scanned from the banking app |
| PromptPay | promptpay | Thailand | QR scanned from the banking app |
All seven share one API shape: POST /v1/payments → requires_action → the hosted page runs the rail-specific handshake → payment.succeeded within seconds of approval.
UPI deep dive
UPI moves money between Indian bank accounts through a customer-chosen UPI app. For merchant collection the standard pattern is the collect flow: you request money from the customer's virtual payment address (VPA, like anna@okbank), and they approve the request in their app with their UPI PIN. On desktop, the hosted page offers scan-to-pay as well — same rails, QR instead of a push:
Practical notes:
- The collect request expires. Validity is set by the rails — minutes, not hours. The hosted page counts it down and lets the customer re-request; an expired, unapproved request fails the payment.
- Approval is authorization and settlement. When the customer enters their PIN, the debit happens — there is no separate capture step, and
capture_methoddoes not apply. - Amounts are in paise — minor units, like every amount in the API.
419900is ₹4,199.00.
PIX deep dive
PIX is Brazil's instant-payment system: transfers between any two accounts, in seconds, around the clock — weekends included. For checkout, Finscale generates a dynamic QR bound to the exact amount and your reference, plus the equivalent copy-paste "Pix code" for customers on the same device:
- Dynamic beats static. Because the QR encodes amount and reference, reconciliation is exact — no underpaid transfers, no orphaned credits.
- Confirmation is push, not poll. Finscale hears the rail confirm and flips the hosted page and your webhook within seconds. Mobile-to-mobile, the copy-paste code keeps conversion high where scanning isn't possible.
Creating a real-time payment
curl https://api.finscale.dev/v1/payments \
-H "Authorization: Bearer sk_test_51FinscaleDemo…" \
-H "Idempotency-Key: idem_ord_9f21_0716" \
-H "Content-Type: application/json" \
-d '{
"amount": 419900,
"currency": "INR",
"payment_method": "upi",
"reference": "ord_9f21_0716",
"customer": { "email": "anna@example.com" },
"return_url": "https://shop.example.com/checkout/return"
}'
{
"id": "pay_7Nu4pV2rK9Wd",
"object": "payment",
"amount": 419900,
"currency": "INR",
"status": "requires_action",
"payment_method": "upi",
"reference": "ord_9f21_0716",
"provider": "prov_in_psp_01",
"next_action": {
"type": "redirect",
"url": "https://pay.finscale.dev/r/7Nu4pV2r"
},
"created_at": "2026-07-16T09:24:31Z",
"livemode": false
}
Send the customer to next_action.url; the hosted page runs the VPA/QR handshake for whichever method you passed. The pattern is identical for pix, blik, swish, mb_way, paynow, and promptpay — only the on-page experience changes.
BLIK, Swish, MB WAY, PayNow, PromptPay
- BLIK — the customer opens their Polish banking app, generates a 6-digit code, types it on the hosted page, then confirms the push in the app. Two-step, but domestic conversion is excellent.
- Swish / MB WAY — the customer enters their phone number; the payment request lands in the Swish or MB WAY app for approval. The number identifies the account.
- PayNow / PromptPay — QR-first: the hosted page shows a QR the customer scans from any participating banking app. Confirmation semantics match PIX.
Adjacent rails
Three catalog methods share the push model but aren't instant-rail checkouts, and are worth knowing here:
| Method | payment_method | How it differs |
|---|---|---|
| M-Pesa | mpesa | Mobile money (Kenya): a payment prompt is pushed to the customer's phone; they approve with their M-Pesa PIN and the debit comes from their mobile-money balance. Confirmation in seconds — closest cousin to UPI. |
| SPEI | spei | Bank transfer (Mexico): the hosted page shows a transfer reference (CLABE); the customer pushes a credit transfer from their banking app. Typically confirms in minutes. |
| SEPA Credit Transfer | sepa_credit | Bank transfer (EU): customer pushes a credit transfer carrying your reference. Settles same-day to next business day — the slow, high-trust end of the push family. |
Refunds — and no chargebacks
POST /v1/refunds works unchanged: full or partial, by payment id. On instant rails the refund travels as a reverse transfer on the same rail, so it typically lands in the customer's account within minutes — watch refund.succeeded. See Refunds.
Settlement timing
The rail settles customer-to-Finscale in seconds; your funds then follow the normal payout schedule — unified with the rest of your volume, one payout per currency at T+2. Instant rails make the confirmation instant, not the payout: cash-flow planning still keys off the settlement report.
Error scenarios
| Scenario | What the API does |
|---|---|
| Collect request or QR expires unapproved | The payment moves to failed; payment.failed fires with the normalized failure_code. Create a fresh payment to retry — sessions are single-use. |
| Customer declines the request in-app | Immediate payment.failed. A decline by the customer is final — no failover. |
| Account can't cover the amount | payment.failed with failure_code: "insufficient_funds". |
| Wrong currency for the rail | 400 invalid_request_error with currency_not_supported at create — UPI is INR-only, PIX is BRL-only, and so on. |
| Rail outage | Retriable infrastructure failures fail over across capable providers automatically; a rail-wide outage surfaces as provider.health.changed — see Provider health. |
Related
- Payment methods overview — families, payload shapes, full catalog
- Bank redirects — the browser-redirect branch of account-to-account
- Webhooks — the delivery guarantees your fulfillment depends on
- Reconciliation — matching rail confirmations to settlement lines
- Method catalog on finscale.dev — regions and currencies