Skip to main content

Goal

Fund a customer’s Bastion account with USDC by converting USD wired from their bank account, using an on-ramp conversion via a Virtual Account (VA).
Scope: USD → USDC, Wire only, US customers only, first-party (customer wires from their own bank account).

Key entities


Flow overview

The steps to fund a stablecoin balance from a bank account are:
  1. Create a Virtual Account
  2. Share deposit instructions with the customer
  3. Customer wires USD
  4. Track conversion status
  5. Show balance
Unlike off-ramps, the partner does not call POST /v2/conversions. The conversion is auto-created the moment Bastion detects the incoming wire.

Prerequisites

  • Customer has a verified identity (KYC or KYB) with fiat_operations_enabled = true
  • Customer has an active Bastion account on a supported chain
  • You have an API key and registered webhook

Step 1 – create a virtual account

Create a Virtual Account for the customer. Each VA links to a specific chain, asset, and destination wallet; create one VA per chain and asset you want to support. Request
Field notes Response
Store the id as virtual_account_id so you can reference this VA later. You can retrieve it again at any time from the GET /v2/identities/{identity_id}/virtual-accounts list endpoint.

Step 2 – share deposit instructions with the customer

Present the deposit_instructions from Step 1 to the customer so they can initiate a wire from their bank. Fields to surface in your UI The bank_account_number is unique to this VA. The customer does not need to include a memo or reference — the account number alone routes the deposit to the correct VA.

Step 3 – customer wires USD

The customer initiates a domestic wire from their bank to the deposit instructions shared in Step 2. When the wire lands at Bastion’s banking partner, Bastion detects it and auto-creates a conversion record. No API call is required from your platform at this step.

Step 4 – track conversion status

Once the wire is detected, Bastion creates the conversion and fires webhooks as it progresses. You learn the conversion_id from the first webhook.

Option A: webhooks

Example event (INITIATED)
Example event (COMPLETED)
Status progression The on-ramp progression is: INITIATEDPROCESSINGPAYOUT_INITIATEDPAYOUT_IN_PROGRESSCOMPLETED Handle statuses:
Webhook reliability: Failed deliveries are retried with exponential backoff (15 s base interval, 10 min max). Deduplicate using id + status. If no webhook arrives within a reasonable window, poll GET /v2/conversions/{conversion_id}.

Option B: polling

If webhook delivery fails, list conversions by account to find the record:
Then poll GET /v2/conversions/{conversion_id} for status updates.

Step 5 – show updated balance

After the conversion completes, refresh balances and show the on-ramp in the customer’s history. Refresh balances
UI recommendations:
  • Increase visible USDC balance by destination.amount from the completion webhook
  • Display USD wired (gross), fees, USDC delivered (net), and status
  • Show source (masked bank account details from the wire)

Fees

fees_total on the conversion reflects the incoming wire fee only. The fee is deducted from the wired USD amount before USDC is delivered. Example: customer wires $500 → fees_total = 14.00destination.amount = 486.00 USDC delivered. The fees array is populated from the moment the conversion is created (when the wire lands). Developer fees are not supported yet.

Implementation notes