Rails-first vs chain-first: choosing between an abstracted and an advanced blockchain payments API

Rails-first or chain-first? How BlindPay's Abstracted and Advanced API flavors differ, what changes in your code, and a go-live checklist for both.

Rails-first or chain-first is a choice about what your code talks to. An abstracted blockchain payments API speaks in bank terms: virtual accounts, payins, and payouts over ACH, wire, SWIFT, Pix, or SPEI, with stablecoins settling underneath. An advanced API exposes wallets, chains, tokens, and on-chain authorization. BlindPay documents one API in both flavors.

If you are still deciding whether you need a blockchain at all, start with blockchain payments vs crypto payments. This page assumes you are building and want to pick an integration shape.

Key takeaways

  • Abstracted means bank-rail concepts. Advanced means wallets, chains, and tokens. Same API, same keys.
  • Pick by where your users' money lives: in bank accounts, or in wallets they control.
  • External wallets authorize each payout on-chain: ERC-20 approve, a signed Stellar XDR, or a Solana delegation.
  • Development instances use USDB on testnets and complete payouts automatically.
  • Go live with five things in place: webhooks, idempotency, error handling, reconciliation, monitoring.

What are the Abstracted and Advanced flavors?

They are two ways of reading the same BlindPay API. The overview page has both: the Abstracted flavor describes bank rails, and the Advanced flavor describes the stablecoin mechanics.

Definition: An abstracted payments API presents payment-rail objects (bank accounts, deposits, payouts) and handles the blockchain leg internally. An advanced payments API exposes that leg: which wallet holds funds, which chain and token settle the transfer, and how the sender authorizes it.

In the Abstracted flavor, every dollar or real still settles through stablecoins, but BlindPay manages the conversion step. You never sign anything on-chain. In the Advanced flavor, you choose between BlindPay-managed wallets and customer-controlled wallets, pick networks and tokens, and handle authorization per chain.

The docs switch flavor with a query parameter, so /docs/payouts?flavor=abstracted and /docs/payouts?flavor=advanced are the same page through two lenses.

How does Store, Receive, Send look in each flavor?

The same three verbs, described two ways. This table summarizes BlindPay's Store, Receive, and Send pages plus payins and payouts.

VerbAbstracted readingAdvanced reading
StoreA balance BlindPay holds for the customer (managed wallet)A managed wallet (bl_..., custodial, beta) or an external blockchain wallet (bw_..., customer-controlled)
ReceiveA bank deposit (ACH, wire, SWIFT, Pix, SPEI, Transfers, PSE) becomes a payinStablecoins arrive in a managed wallet, tracked by wallet.inbound; or a payin delivers stablecoins to any registered wallet
SendA payout to a bank account over ACH, wire, RTP, SWIFT (POBO/COBO), Pix, SPEI, ACH COP, Transfers, SEPA, or Faster PaymentsStablecoins move out of a managed wallet to another address, or are pulled from a wallet to fund a fiat payout

The Abstracted flavor maps to what a finance team already knows. The Advanced flavor maps to what a crypto-native product already does. Neither one is the beginner version.

What changes in your code between the two?

Mostly the funding step of a payout. Everything before it (customer, bank account, quote) and after it (status, webhooks) is the same.

Every payout starts with a payout quote: a bank_account_id, a network and token for the funding leg, currency_type, cover_fees, and request_amount in minor units. The quote locks the rate and fees for 5 minutes. Then the funding source decides the next call:

Funding sourceAuthorizationExecute call
BlindPay-managed walletNone, BlindPay moves the fundsPOST /payouts/evm with the quote ID and the wallet address, on any supported chain
External wallet on an EVM chainERC-20 approve for the amount in the quote's contract objectPOST /payouts/evm with the quote ID and sender address
External wallet on StellarPOST /payouts/stellar/authorize returns an unsigned transaction; you sign the XDRPOST /payouts/stellar
External wallet on SolanaPOST /prepare-delegate-solana, then sign and submit the delegationPOST /payouts/evm with the quote ID and Solana address

The three authorization methods match each chain's own token model. EIP-20 defines approve as allowing a spender to withdraw up to a set value. Solana's token program lets an account owner delegate authority over some or all of a balance with the Approve instruction. Stellar encodes transactions in XDR, so the sender signs a payment transaction instead of granting an allowance.

Quotes and approvals are single-use. To send again, quote again and authorize again. The per-chain tutorials are payout with EVM, payout with Stellar, and payout with Solana.

Which chains and tokens can you use?

Nine chains, with token support that varies by chain. The supported chains reference is the source of truth for network and token values; check it rather than the shorter tables inside individual guides.

ChainMainnet stablecoinsDevelopment testnet
EthereumUSDC, USDTEthereum Sepolia
PolygonUSDC, USDTPolygon Amoy
BaseUSDCBase Sepolia
ArbitrumUSDCArbitrum Sepolia
TempoUSDC, USDTTempo Testnet
ArcUSDCArc Testnet
StellarUSDCStellar Testnet
SolanaUSDC, USDTSolana Devnet
TronUSDTnone

Production instances accept only USDC or USDT on mainnets. Development instances accept only USDB on testnets, and a mismatched pair is rejected. Tron has no testnet, so Tron flows can only be exercised in production.

In the Advanced flavor you can also move USDC between managed wallets across Ethereum, Polygon, Base, Arbitrum, and Arc with Circle's CCTP v2, which burns USDC on the source chain and mints it on the destination. Other tokens stay on the same network. If the newer chains are unfamiliar, payment blockchains like Tempo and Arc explains what they are.

Which flavor fits your product?

Decide by who holds the money between steps. Five common shapes:

ProductFlavorWhy
Payroll or contractor payouts funded by bank transferAbstractedUsers never see a wallet; deposit, hold a balance, pay out
A US account for customers abroad (collections)AbstractedVirtual accounts and payins are bank objects
A crypto wallet app adding cash-out to local banksAdvancedUsers already control wallets; payouts are authorized from them
A treasury tool moving USDC between chainsAdvancedTransfers, networks, and CCTP routes are the product
A platform doing bothBothAbstracted screens for finance users, Advanced flows for crypto users

Custody follows from the choice. BlindPay operates as a non-custodial payment processor for payout flows from customer-controlled wallets: you authorize the exact amount and BlindPay executes that single transaction. If a payout cannot be delivered after the stablecoins are collected, BlindPay refunds them to the quote's refund wallet, or to the sending wallet when none is set; on Pix and other non-USD local rails the refund is automatic, while USD payouts and payouts whose review times out are refunded after an operator review. Optional BlindPay-managed wallets (beta) are custodial when you choose that path. The wallet custody comparison covers the trade-offs.

How do you test both flavors before going live?

On a development instance, which behaves like production without real money. Per the sandbox vs production guide:

  • Every customer is auto-approved. Name one Fail to test a rejection.
  • Wallets use USDB, funded by a payin that auto-completes about 30 seconds after creation.
  • Payouts still run the on-chain authorization step, then complete automatically with no real bank transfer.
  • A payout quote with request_amount of 66600 forces failed, and 77700 forces refunded.

Run each flavor's happy path, then both forced outcomes, and confirm your webhook handler, database, and user-facing screens all agree. What sandbox testing misses lists the gaps to cover in production.

What belongs on the go-live checklist?

Five areas, the same for both flavors. Tick every line before the first production payout.

1. Webhooks

  • Register an https endpoint per instance; BlindPay allows up to 25.
  • Verify svix-id, svix-timestamp, and svix-signature against the raw body, and reject timestamps outside a 5-minute window (verification docs).
  • Deduplicate on svix-id, which stays the same across redeliveries.
  • For payouts, handle payout.new, payout.update, and payout.complete, and branch on status, since a failed payout can arrive as an update.

2. Idempotency

  • Send an Idempotency-Key header on every POST, PUT, PATCH, and DELETE.
  • Retry with the exact same body bytes. A different body returns 422 idempotency_key_payload_mismatch.
  • Respect 409 idempotency_key_in_flight and its Retry-After header. Keys last 24 hours (idempotency docs).

3. Error handling

  • Treat an expired quote as normal: re-quote, show the new numbers, ask again. Never execute a stale quote.
  • Map a 400 on an unsupported network and token pair to a configuration bug, not a user error.
  • Expect SWIFT payouts to third parties to start on_hold until compliance documents are approved.

4. Reconciliation

  • Store amounts in minor units, exactly as the API returns them.
  • Keep your own payment ID next to the BlindPay quote, payout, or payin ID, and the on-chain transaction hash from the tracking objects.
  • Run a daily job that matches your ledger to payout and payin statuses. The webhooks and reconciliation guide has the matching logic.

5. Monitoring

  • Alert on payouts in on_hold or processing longer than the rail's documented window.
  • A failed payout, or one sitting past review, does not refund on its own. Contact support rather than wait.
  • Use separate API keys for development and production, restrict production keys to your server IPs with ip_whitelist, and rotate by deleting and recreating a key (API keys docs).

Then send one small production payout on each rail you plan to use, and watch it all the way to completed.

What to do next

Pick the flavor that matches where your users' money lives, then run its happy path and both forced outcomes on a development instance. If you are still comparing vendors, read the best blockchain payment processors for fintechs first.

Open the BlindPay payout quickstart, pick your flavor, and send a USDB test payout today.

FAQ