Back to Prompts

Integrate the BlindPay wallet

Hold customer stablecoin balances in BlindPay-custodied wallets: create the wallet, collect payins into it, pay out from it with no signing step.

Payins
Payouts
Quotes
Compliance
Webhooks

Paste this prompt into your coding agent to build on the BlindPay wallet: BlindPay generates the address and holds the keys, so your customers get a balance inside your product with no browser wallet and no transaction signing.

Prompt

text
You are integrating the BlindPay wallet (the managed, BlindPay-custodied wallet) into my application: BlindPay creates and custodies a wallet per customer, and I move money through it with plain API calls, never with private keys or signatures on my side.

Before writing code, read these sources and follow them over any prior knowledge:
- https://blindpay.com/docs/llms.txt (read the managed wallets, payins, payouts, send, and webhooks pages)
- The OpenAPI spec: curl https://api.blindpay.com/doc

Build the flow:
1. Prerequisites: an approved customer (kyc_status "approved"). Managed wallets are in beta; support only the chains the docs list (Ethereum, Base, Polygon, Arbitrum, Solana) with USDC/USDT, and USDB on development testnets. Stellar and Tron are not supported for managed wallets; if I need those, fall back to blockchain wallets instead.
2. Create the wallet: POST /v1/instances/{instance_id}/customers/{customer_id}/wallets with network, name, and my database ID as external_id. BlindPay generates the address server-side. Persist both the id (bl_) and the address against my user record: payin quotes reference the id, payouts reference the address. A customer can hold up to 10 wallets; enforce that in my schema. Never confuse bl_ (managed wallet) with bw_ (blockchain wallet) when passing IDs into quotes or payouts.
3. Show the balance: GET /v1/instances/{instance_id}/customers/{customer_id}/wallets/{wallet_id}/balance. Treat this endpoint as the source of truth for available funds and check it before quoting any outbound movement.
4. Money in, two paths:
   a. Fiat payin: POST /v1/instances/{instance_id}/payin-quotes with wallet_id (not blockchain_wallet_id), then POST /payins/evm with the resulting payin_quote_id. Stablecoins settle into the wallet; confirm with payin.complete and wallet.inbound webhooks.
   b. Direct stablecoin deposit: share the wallet address; any USDC/USDT transfer on the matching network credits it and fires wallet.inbound. Warn users that deposits on the wrong chain are lost.
5. Money out, two paths:
   a. Fiat payout: POST /v1/instances/{instance_id}/quotes for a payout quote, then POST /payouts/evm with quote_id and the managed wallet's address as sender_wallet_address before expires_at. Because BlindPay custodies the wallet there is no ERC-20 approve and no signature step; the payout is a single call.
   b. Stablecoin transfer: POST /v1/instances/{instance_id}/transfer-quotes then POST /transfers to move funds to another wallet or external address. The transfer quote expires in 5 minutes, so quote and execute in one server-side sequence. Only USDC crosses chains (Circle CCTP v2 between Ethereum, Polygon, Base, Arbitrum); everything else needs the same network on both sides.
6. Drive state from Svix-verified webhooks (svix-id, svix-timestamp, svix-signature against the raw body): wallet.new on creation, wallet.inbound on deposits, payin.new/complete, payout.new/update/complete, transfer.new/complete. Reconcile every event back to my user via the bl_ ID or external_id.
7. Handle the unit mismatch explicitly: wallet.inbound reports amount scaled by 100 (100 means $1.00) while the balance endpoint reports the raw amount. Normalize both into one internal representation with a documented conversion, and never compare them directly.
8. Test end to end on a development instance: KYC auto-approves, USDB works on every dev testnet, and payout sentinel amounts verify all outcomes ($666.00 forces a failed payout, $777.00 forces a refunded one).

Constraints:
- API keys stay server-side; never expose instance or customer IDs in client code paths that don't need them.
- Amounts are integers in minor units everywhere; never use floating point for money.
- Idempotency on money movement: key payins, payouts, and transfers on my own transaction ID and check for an existing record before creating.
- wallet.inbound only fires for USDC and USDT; don't rely on it for other tokens.

Deliverables: wallet provisioning service with the bl_/address persistence, balance display wired to the balance endpoint, payin-to-wallet and payout-from-wallet flows, the transfer path with the 15-second quote handled, webhook handlers with unit normalization, and a passing end-to-end test on the development instance covering deposit, payout, failed, and refunded cases.

How to use

  1. Paste the prompt with your stack details and which chains you actually need.
  2. Decide the wallet-per-customer model up front: one balance wallet per user is the common case; the 10-wallet cap matters only for multi-currency or multi-chain designs.
  3. Run the sentinel-amount payout tests on a development instance before touching production; the unit mismatch between wallet.inbound and the balance endpoint is the most common reconciliation bug.