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

Methodpayment_methodRegionCustomer experience
UPIupiIndiaCollect request to a VPA, or scan-to-pay QR; approve with UPI PIN
PIXpixBrazilDynamic QR / copy-paste Pix code in any bank app
BLIKblikPoland6-digit code from the bank app, then in-app confirm
SwishswishSwedenPhone number + approval in the Swish app
MB WAYmb_wayPortugalPhone number + approval in the MB WAY app
PayNowpaynowSingaporeQR scanned from the banking app
PromptPaypromptpayThailandQR scanned from the banking app

All seven share one API shape: POST /v1/paymentsrequires_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:

Customer's UPI app Hosted page Finscale UPI rails enters VPA — or scans the QR VPA collect request push: payment request awaiting approval approves with UPI PIN confirmed — seconds webhook: payment.succeeded The collect request has a rail-defined validity of a few minutes; unapproved requests lapse and the payment fails.

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_method does not apply.
  • Amounts are in paise — minor units, like every amount in the API. 419900 is ₹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:

Customer's bank app Hosted page Finscale PIX rails dynamic QR + copy-paste Pix code scans & confirms in the bank app transfer executed — instant, 24/7 webhook: payment.succeeded page flips to “paid” in real time The dynamic QR encodes the exact amount and reference — no typos, no partial payments. It expires with the session if unpaid.
  • 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

POST /v1/payments — UPI
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"
  }'
201 Created
{
  "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:

Methodpayment_methodHow it differs
M-PesampesaMobile 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.
SPEIspeiBank 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 Transfersepa_creditBank 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.

No chargeback rail Every payment on this page is customer-initiated and bank-authenticated (PIN, app approval, or banking-app QR). None of these schemes has a chargeback mechanism — approved means final.

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

ScenarioWhat the API does
Collect request or QR expires unapprovedThe 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-appImmediate payment.failed. A decline by the customer is final — no failover.
Account can't cover the amountpayment.failed with failure_code: "insufficient_funds".
Wrong currency for the rail400 invalid_request_error with currency_not_supported at create — UPI is INR-only, PIX is BRL-only, and so on.
Rail outageRetriable infrastructure failures fail over across capable providers automatically; a rail-wide outage surfaces as provider.health.changed — see Provider health.