Neobank API quickstart: from sign-up screen to first deposit and first payout

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

  • Start on a development instance: KYC auto-approves, virtual accounts are created approved, and payins settle on their own in about 30 seconds.
  • Every API call belongs to a screen. If you can't name the screen, the call is in the wrong place.
  • The user's balance lives in your ledger. Webhooks tell you when to move it.
  • Quotes expire in about 5 minutes. Build the re-quote path before you build the happy path.
  • Send an Idempotency-Key on every call that moves money.

What do you need before the first call?

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:

Bash
curl https://api.blindpay.com/v1/instances/in_000000000000/customers \
  -H "Authorization: Bearer YOUR_API_KEY"

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.

Which API call sits behind each screen?

One call per screen, nine in total. Paths below are relative to /v1/instances/in_.../ except the terms link.

App screenMethod and pathKey fieldsWhat the screen waits for
1. Accept termsPOST /v1/e/instances/in_.../tosidempotency_key (a UUID)tos_id on your redirect URL, or the tos.accept webhook
2. Verify identityPOST customerstos_id, type, kyc_type, name, date of birth, tax_id, address, ID document, selfiekyc_status: approved
3. Set up balancePOST customers/re_.../blockchain-walletsnetwork, is_account_abstraction, address or signed messagebw_ id returned
4. Show account detailsPOST customers/re_.../virtual-accountstoken, blockchain_wallet_idstatus: approved and the virtualAccount.complete webhook
5. Deposit receivednone, a deposit creates a payinpayin id, amounts, feespayin.complete webhook
6. Add recipientPOST customers/re_.../bank-accountstype plus the rail's fieldsbankAccount.new webhook
7. Review transferPOST quotesbank_account_id, request_amount in cents, currency_type, cover_fees, network, tokenquote id and expiry
8. Confirm transferPOST payouts/evmquote_id, sender_wallet_addresspayout.new webhook
9. Transfer statusGET payouts/po_... or webhooksstatuspayout.complete webhook

The full field lists live in the payout quickstart, the customers reference, and create a virtual account.

How do terms and KYC work on screens 1 and 2?

The user accepts BlindPay's terms on a hosted page, then you create the customer with their KYC data.

  1. Your backend requests a terms link and the app opens it. Acceptance only works from the user's browser at app.blindpay.com; server-side acceptance is ignored, per the terms of service docs.
  2. BlindPay redirects to your redirect_url with a tos_id. Store it.
  3. Create the customer with the tos_id and identity data. The status starts as verifying.
  4. KYC Standard typically resolves in about 60 seconds. KYC Enhanced and KYB wait for manual review. Show "verifying" with a realistic time, not a spinner that never ends.
  5. On rejection, read kyc_warnings and fraud_warnings, explain what to fix, and create a new customer with corrected data. Existing customers can't be re-submitted.

The design of this funnel (screen order, drop-off, tiered limits) is covered in neobank KYC and KYB onboarding.

How do screens 3 and 4 give the user a US account?

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.

How do you credit the first deposit on screen 5?

You don't call anything. A deposit to the account creates a payin, and your webhook handler credits the ledger.

  1. Receive the webhook and verify the signature (svix-id, svix-timestamp, svix-signature), as the Svix verification guide and BlindPay's webhook verification docs describe.
  2. Store the event id. Webhooks can arrive twice.
  3. On payin.new, show a pending line in the history.
  4. On payin.complete, move the amount to available, keyed on the payin id so a duplicate event can't credit twice.

The ledger side, pending versus available and how to post the entries, is in neobank deposit to balance.

How do screens 6 to 9 send the first payout?

Save a bank account, quote, confirm, execute, then track.

  • Save the recipient. Each rail has its own fields: ACH needs routing and account numbers plus address and compliance fields, Pix needs a pix_key (CPF, CNPJ, phone, email, or random key). A customer can pay a third party's account. US users can link a bank through Plaid Auth on instances where BlindPay enables it.
  • Quote. request_amount is in cents (1000 means 10.00). currency_type says whether the amount is what the sender sends or what the recipient gets. cover_fees decides who pays the fee.
  • Confirm. Show the receiver amount, the fees, and a countdown. The quote expires in about 5 minutes.
  • Execute. Call payouts/evm with the quote_id and the sender wallet. A BlindPay-managed wallet needs no signing. A customer-controlled EVM wallet approves the quoted amount on-chain first.
  • Track. payout.new fires when the stablecoins are collected, payout.complete when the payout finishes, fails, or is refunded.

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.

How do you test the whole loop?

On a development instance, with magic amounts.

TestHowExpected
Happy depositCreate a payin quote and payin, wait about 30 secondspayin.complete, balance credited once
Happy payoutAny amount other than the two belowpayout.complete
Failed payoutrequest_amount 66600Status failed, error screen shown
Refunded payoutrequest_amount 77700Status refunded, funds back in the wallet
Expired quoteWait past the expiry, then executeError, app re-quotes and asks again
Duplicate webhookReplay an eventLedger 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.

What goes on the go-live checklist?

  • Production instance onboarded (KYB done in the dashboard) and a production API key in secrets.
  • Webhook endpoint registered for production, signature checks on.
  • Every money-moving call sends an Idempotency-Key.
  • Re-quote path tested for expired quotes.
  • Failed and refunded payout screens written and checked with support.
  • Customer limits and limit increase flow understood (limit increases).
  • One real deposit and one real payout run by an employee before the first user.

Which errors trip teams up first?

SymptomLikely causeFix
Customer stuck in verifyingKYC Enhanced or KYB, manual reviewShow the expected wait; don't create duplicates
Virtual account create rejectedCustomer not approved yet, or wallet belongs to another customerWait for approved; use the same customer's wallet
Account details emptyAccount not approved yetWait for virtualAccount.complete
Payout execute failsQuote expiredRe-quote and re-confirm
Amount off by 100xSent dollars instead of centsConvert to integer cents
Balance credited twiceWebhook replayKey ledger entries on the payin id

How BlindPay fits

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.

What to do next

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.

FAQ