> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stableyard.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# On-ramp accounts: US bank details that convert to stablecoin

> Issue US bank details for one account. Every transfer in arrives as stablecoin in the account's wallet.

An on-ramp account gives one customer their own US bank details. Every transfer sent to them is converted to USDC and delivered on-chain to a wallet the account has linked. There is no per-transfer call and no settlement step.

In the API it is an `OnrampBankAccount`, with an id prefixed `onramp_acct_`. Other pages call it a virtual account. Each inbound transfer has its own funding transaction and `bank_funding.*` events; it does not require a new receive Payment.

```mermaid theme={null}
sequenceDiagram
  participant B as Your backend
  participant S as Stableyard
  participant C as Customer
  participant W as Customer's wallet
  B->>S: GET onramp-bank-account-requirements
  B->>S: POST onramp-bank-accounts
  S-->>B: status active
  B->>S: GET deposit-instructions
  B->>C: Show the bank details
  C->>S: ACH, Fedwire or FedNow transfer
  S->>W: USDC, converted by a banking partner
  S-->>B: bank_funding.completed
```

## When to use it

Use it when a customer funds repeatedly and should do it the way they pay any bill: a transfer from the bank they already use. It is a standing facility, not a session. The details do not change, so a customer can save them as a payee.

For one payment by a payer with no stablecoin, use fiat at checkout instead. See [On-ramps](/payments/on-ramps).

## What it needs

| Requirement | How to meet it |
| - | - |
| Your organization's KYB is approved | `compliance.partnerKyb.status` in `GET /v2/partners/config` |
| The on-ramp is enabled for your app with a US route | `available` in the requirements response below |
| An active banking relationship on the account | Activate `bank_onramp`. See [Capability activation](/concepts/capability-activation) |
| A connected wallet on a verified destination chain and asset | `destinations` in the requirements response below |

An `individual` gets the banking relationship through identity verification and the hosted form. A `business` gets it through hosted business verification.

## Check what can be issued

Call these endpoints from your backend with the `v2:payments` scope. Check requirements before showing the flow. Missing routes, access or eligible wallets return `available: false` with a reason. Authentication, storage and unexpected routing failures use normal HTTP errors; handle those separately from unavailable configuration.

```bash theme={null}
curl https://prod-api.stableyard.fi/v2/accounts/acct_123/onramp-bank-account-requirements \
  -u "$APP_ID:$APP_SECRET"
```

```json theme={null}
{
  "accountId": "acct_123",
  "available": true,
  "recipientOnFile": true,
  "unavailableReason": null,
  "rails": [
    { "rail": "ach", "country": "US", "currency": "USD" },
    { "rail": "fedwire", "country": "US", "currency": "USD" }
  ],
  "recipientTypes": ["individual", "business"],
  "destinations": [
    { "connectedWalletId": "wallet_123", "chainId": 42161, "address": "0x1111111111111111111111111111111111111111", "label": "Primary wallet", "assetCodes": ["USDC"] }
  ],
  "supportedDestinations": [
    { "chainId": 42161, "networkName": "Arbitrum", "assetCodes": ["USDC"] }
  ]
}
```

| Field | Read it for |
| - | - |
| `rails` | Rails with an operational route in this environment. One rail can be live while another is not |
| `recipientOnFile` | Whether a verified recipient name and address are available. When true, omit all recipient fields at issuance to reuse them |
| `destinations` | This account's connected wallets that can receive, with the assets verified for each chain |
| `supportedDestinations` | The delivery chains and assets allowed in this environment, even when the account has no eligible wallet yet |

| `unavailableReason` | Meaning |
| - | - |
| `onramp_route_not_configured` | No US route is operational for your app in this environment |
| `no_eligible_destination` | The account has no connected wallet on a verified chain. Use `supportedDestinations` to tell the customer which wallet to link, then read again |

Choose the wallet and asset from these lists, not from the general network catalog. None of them replaces the account's `bank_onramp` approval.

## Issue it

When `recipientOnFile` is true, the verified recipient details can be reused:

```bash theme={null}
curl -X POST https://prod-api.stableyard.fi/v2/accounts/acct_123/onramp-bank-accounts \
  -u "$APP_ID:$APP_SECRET" \
  -H "Idempotency-Key: onramp:acct_123:v1" \
  -H "Content-Type: application/json" \
  -d '{
    "connectedWalletId": "wallet_123",
    "destinationAssetCode": "USDC",
    "rail": "ach"
  }'
```

```json theme={null}
{
  "id": "onramp_acct_123",
  "accountId": "acct_123",
  "status": "active",
  "rail": "ach",
  "sourceAsset": "USD",
  "destinationAssetCode": "USDC",
  "destinationChainId": 42161,
  "connectedWalletId": "wallet_123",
  "bankName": "Example Bank",
  "accountNumberLast4": "5543",
  "createdAt": "2026-10-01T12:00:00Z"
}
```

| Field | Required | Notes |
| - | - | - |
| `connectedWalletId` | Yes | A wallet from `destinations`. Fixed once issued |
| `destinationAssetCode` | Yes | Use the asset returned for that wallet in `destinations`; the current allowlist is USDC. Fixed once issued |
| `rail` | No | `ach`, `fedwire` or `fednow`. Defaults to `ach` |
| `recipientType` | Conditional | `individual` or `business`; send all three recipient fields together |
| `recipientName` | Conditional | Up to 200 characters; send all three recipient fields together |
| `recipientAddress` | Conditional | `street1`, `city`, `region`, `postalCode` and a two-letter `country`; `street2` and `street3` optional |

Omit all three recipient fields to use the verified details on file, or send all three together to override them. A partial override is rejected. When `recipientOnFile` is false, supply the full recipient details; omitting them returns `400` with `details.reasonCode: "onramp_recipient_details_required"`.

The response shows only the bank name and the last four digits. The full details come from deposit instructions.

**One per account, and its routing is fixed.** An account holds one on-ramp account per banking partner. Asking again with the same wallet, chain and asset returns the existing one. Asking with a different one is refused with `409`, and `details` names the routing already issued. An issued account cannot be re-pointed; Stableyard support can retire it so another can be issued.

**Retry with the same key.** `Idempotency-Key` is required and must contain 8–256 printable characters after trimming surrounding whitespace. Repeating the original body with the same key after a timeout or a `provisioning` response resumes the same issuance and never issues a second account.

## Statuses

```mermaid theme={null}
stateDiagram-v2
  [*] --> provisioning: POST onramp-bank-accounts
  provisioning --> active: bank details issued
  active --> disabled: disabled by the banking partner
  disabled --> active: re-enabled
```

| `status` | Can receive transfers | Meaning |
| - | - | - |
| `provisioning` | No | Issuance has started. Repeat the request with the same key to resume it |
| `active` | Yes | Bank details are live. Deposit instructions are available |
| `requires_intervention` | No | Stopped for Stableyard operations review |
| `disabled` | No | Turned off by the banking partner |
| `retired` | No | Withdrawn by Stableyard. It no longer counts toward the one-per-account limit, so a new account can be issued, and funding that still arrives is picked up for 30 days |

## Show the deposit instructions

```bash theme={null}
curl https://prod-api.stableyard.fi/v2/accounts/acct_123/onramp-bank-accounts/onramp_acct_123/deposit-instructions \
  -u "$APP_ID:$APP_SECRET"
```

```json theme={null}
{
  "id": "onramp_acct_123",
  "accountId": "acct_123",
  "rail": "ach",
  "acceptedRails": ["ach", "fedwire"],
  "currency": "USD",
  "destination": { "assetCode": "USDC", "chainId": 42161 },
  "beneficiary": { "name": "Jane Customer" },
  "bank": {
    "name": "Example Bank",
    "abaRoutingNumber": "101019644",
    "accountNumber": "9990005543",
    "accountType": "checking"
  }
}
```

`beneficiary.name` is the account holder name the sender puts on the transfer. Show every field exactly as returned.

`rail` is the rail requested at issuance. `acceptedRails` lists every rail these instructions can accept, limited to those issued on the facility and enabled for your app. Use that list when showing the sender how to transfer.

<Warning>
  This is the only response with the full account number. Call it from your backend, show it to the account holder, and never log, cache or store it. It is served with `Cache-Control: no-store, private`, and any status other than `active` returns `409`.
</Warning>

## Track each transfer

Every transfer in becomes one bank funding transaction, listed newest first.

```bash theme={null}
curl "https://prod-api.stableyard.fi/v2/accounts/acct_123/onramp-bank-accounts/onramp_acct_123/transactions?limit=50" \
  -u "$APP_ID:$APP_SECRET"
```

```json theme={null}
{
  "onrampBankAccountId": "onramp_acct_123",
  "transactions": [
    {
      "id": "onramp_txn_123",
      "onrampBankAccountId": "onramp_acct_123",
      "status": "succeeded",
      "sourceAmount": "250.00",
      "sourceAsset": "USD",
      "destinationAmount": "249.50",
      "destinationAssetCode": "USDC",
      "destinationTxHash": "0x…",
      "failureCode": null,
      "createdAt": "2026-10-02T15:04:00Z",
      "settledAt": "2026-10-02T15:09:00Z"
    }
  ]
}
```

| `status` | Meaning |
| - | - |
| `pending` | The transfer was seen and has not started converting |
| `processing` | It is being converted and delivered |
| `succeeded` | Stablecoin was delivered. `destinationTxHash` can appear a short time after |
| `failed` | It could not be converted. Read `failureCode` |

Amounts are decimal strings. Repeated event delivery must not credit the same funding transaction twice. This list is the source of truth behind the `bank_funding.*` webhooks. `limit` runs from 1 to 100, default 50.

List every on-ramp account an account holds with `GET /v2/accounts/{accountId}/onramp-bank-accounts`.

## When setup is interrupted

| What happened | Do this |
| - | - |
| A timeout, or a `provisioning` response | Repeat the original body with the same `Idempotency-Key` |
| The hosted `bank_onramp` link expired, or `compliance_in_progress` and the page is gone | Activate `bank_onramp` again with a new `Idempotency-Key` |
| The banking partner is still reviewing | Keep reading the capability. Restarting does not speed up a review |

## Errors

| Code | HTTP | When |
| - | - | - |
| `not_found` | 404 | The connected wallet is not an active wallet on this account |
| `conflict` | 409 | A different wallet, chain or asset than the account already issued; another issuance for this account is in progress; or deposit instructions for an account that is not `active` |
| `idempotency_conflict` | 409 | The same key with a different body |
| `payment_method_not_supported` | 422 | No active banking relationship (`details.reasonCode: "provider_relationship_not_active"`), no US route (`"onramp_route_not_configured"`), or an unverified chain or asset |
| `provider_failure` | 502 | Deposit instructions are temporarily unavailable. Retry |

## Webhooks

The payload carries `accountId`, `onrampBankAccountId`, `transactionId`, `status`, the USD and stablecoin amounts, and `destinationTxHash` when known. It never carries bank details.

| Event | Meaning |
| - | - |
| `bank_funding.completed` | A transfer was converted and delivered to the wallet |
| `bank_funding.failed` | A transfer could not be converted |

## Coverage

Issuance is **US dollars only**, over ACH, Fedwire and FedNow. Production supports USDC on Arbitrum One (`42161`); sandbox supports USDC on Arbitrum Sepolia (`421614`). The examples above use the production base URL. For sandbox, use `https://staging-api-v2.stableyard.fi`, sandbox credentials and a wallet returned by that environment’s requirements response. App enablement, account approval and live certification remain separate requirements. See [US bank environments and certification](/supported-regions-and-currencies#us-bank-environments-and-certification).

Stableyard has no endpoint that simulates a deposit, in either environment.

## Related

* [Capability activation](/concepts/capability-activation): the `bank_onramp` approval this needs.
* [Universal Payment Account](/universal-payment-account): the account and wallets it attaches to.
* [Depositing funds](/payments/depositing-funds): every way value arrives in an account.
* [Webhooks](/webhooks): signatures, delivery and retries.

<Card title="Next: Deposit addresses" icon="qrcode" href="/concepts/deposit-addresses">
  Reusable stablecoin addresses with no amount and no expiry.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.