Map every neobank screen to a BlindPay API call: terms, KYC, wallet, US account details, first deposit, bank account, quote, payout, and webhooks.
A neobank integration on BlindPay is nine API calls in a fixed order: terms, customer, wallet, virtual account, payin, bank account, quote, payout, webhooks. Map each one to a screen in your app and you get a user from sign-up to a first dollar deposit and a first local payout, testable end to end on a development instance.
This guide is the screen-by-screen version. For the general developer walkthrough, see integrating a stablecoin API. For the product view of the whole build, start with how to build a neobank.
Key takeaways
A BlindPay account, a development instance, and an API key for it, all created in the dashboard.
API keys are scoped to one instance and shown once at creation, per the API keys docs. A development key doesn't work against production, and the reverse. Keep the key on your server; the mobile app talks only to your backend.
The base URL is api.blindpay.com, and every request carries the key as a bearer token. A first smoke test lists customers on your instance:
If that returns an empty list, you're ready. Use an SDK from the SDKs page (Node.js, Python, Go, PHP, Swift) or generate a client from the OpenAPI 3.1 spec BlindPay serves at api.blindpay.com/doc.
One call per screen, nine in total. Paths below are relative to /v1/instances/in_.../ except the terms link.
| App screen | Method and path | Key fields | What the screen waits for |
|---|---|---|---|
| 1. Accept terms | POST /v1/e/instances/in_.../tos | idempotency_key (a UUID) | tos_id on your redirect URL, or the tos.accept webhook |
| 2. Verify identity | POST customers | tos_id, type, kyc_type, name, date of birth, tax_id, address, ID document, selfie | kyc_status: approved |
| 3. Set up balance | POST customers/re_.../blockchain-wallets | network, is_account_abstraction, address or signed message | bw_ id returned |
| 4. Show account details | POST customers/re_.../virtual-accounts | token, blockchain_wallet_id | status: approved and the virtualAccount.complete webhook |
| 5. Deposit received | none, a deposit creates a payin | payin id, amounts, fees | payin.complete webhook |
| 6. Add recipient | POST customers/re_.../bank-accounts | type plus the rail's fields | bankAccount.new webhook |
| 7. Review transfer | POST quotes | bank_account_id, request_amount in cents, currency_type, cover_fees, network, token | quote id and expiry |
| 8. Confirm transfer | POST payouts/evm | quote_id, sender_wallet_address | payout.new webhook |
| 9. Transfer status | GET payouts/po_... or webhooks | status | payout.complete webhook |
The full field lists live in the payout quickstart, the customers reference, and create a virtual account.
The user accepts BlindPay's terms on a hosted page, then you create the customer with their KYC data.
The design of this funnel (screen order, drop-off, tiered limits) is covered in neobank KYC and KYB onboarding.
Register the wallet that receives USDC, then create a virtual account linked to it.
On EVM networks you can register the wallet by signed message, so BlindPay recovers the address from the signature. On Stellar, Solana, and Tron you pass the address directly. Then create the virtual account with the token (USDC or USDT) and the blockchain_wallet_id.
In production the account moves from pending_review (compliance) to verifying (bank) to approved, and only then carries real numbers. On a development instance it is created approved, with routing number 110000000 and a fake account number, so you can build screen 4 today. The product decisions behind this screen are in giving every neobank customer a US bank account.
You don't call anything. A deposit to the account creates a payin, and your webhook handler credits the ledger.
The ledger side, pending versus available and how to post the entries, is in neobank deposit to balance.
Save a bank account, quote, confirm, execute, then track.
Send an Idempotency-Key header on the payout call, following the pattern in the IETF Idempotency-Key draft and BlindPay's idempotency guide. A retry after a timeout then can't create a second payout.
On a development instance, with magic amounts.
| Test | How | Expected |
|---|---|---|
| Happy deposit | Create a payin quote and payin, wait about 30 seconds | payin.complete, balance credited once |
| Happy payout | Any amount other than the two below | payout.complete |
| Failed payout | request_amount 66600 | Status failed, error screen shown |
| Refunded payout | request_amount 77700 | Status refunded, funds back in the wallet |
| Expired quote | Wait past the expiry, then execute | Error, app re-quotes and asks again |
| Duplicate webhook | Replay an event | Ledger unchanged |
Development instances use USDB, BlindPay's test stablecoin, on testnets. Real routing and real KYC start in production; sandbox vs production lists what changes.
| Symptom | Likely cause | Fix |
|---|---|---|
| Customer stuck in verifying | KYC Enhanced or KYB, manual review | Show the expected wait; don't create duplicates |
| Virtual account create rejected | Customer not approved yet, or wallet belongs to another customer | Wait for approved; use the same customer's wallet |
| Account details empty | Account not approved yet | Wait for virtualAccount.complete |
| Payout execute fails | Quote expired | Re-quote and re-confirm |
| Amount off by 100x | Sent dollars instead of cents | Convert to integer cents |
| Balance credited twice | Webhook replay | Key ledger entries on the payin id |
BlindPay gives a neobank the money movement under these nine screens through one REST API: terms and KYC/KYB, US virtual accounts in the customer's own name, payins, bank accounts, quotes that lock rate and fees, and payouts over ACH, wire, RTP, Pix, SPEI, ACH Colombia, Transfers 3.0, SEPA, Faster Payments, and SWIFT (POBO/COBO). Webhooks are signed with Svix headers. Official SDKs cover Node.js, Python, Go, PHP, and Swift, and the OpenAPI 3.1 spec covers everything else. Operators get a dashboard and a native iOS app.
For payouts from customer-controlled wallets, BlindPay is non-custodial: you authorize the exact amount and BlindPay executes that one transaction. Plans are on the pricing page, and per-transaction fees appear in each quote before you execute.
Create a development instance, then run screens 1 to 9 in order with the payout quickstart open next to your app. When the 66600 and 77700 tests pass, your error screens are real.
Always cheaper? No intermediaries? Recipient needs a wallet? 10 common claims about cross-border stablecoin payments, checked against the Fed and the BIS.
Seven places blockchain payments beat bank rails: contractor payroll, remittances, B2B suppliers, marketplaces, 24/7 treasury, bill pay, and PSP payouts.
The dates that turned stablecoins from a trading tool into cross-border payment rails: USDC, Pix, MiCA, the GENIUS Act, ISO 20022, and Visa settlement.