Ramps
Fiat on-ramps and off-ramps — discover corridors, price a Ramp Quote just-in-time, and hand off to the provider's own execution flow.
SDP wraps ramp providers behind a single pricing step: a Ramp Quote, priced just-in-time against the provider. There is no execute endpoint — SDP quotes the ramp and hands the end-user to the provider's own flow (hosted redirect or funding instructions) to complete it.
Every quote is tied to a Counterparty — the KYC subject for the ramp — and a custody wallet you control. For per-provider configuration, see Ramp providers.
Prerequisites
- A Counterparty. Create one with
POST /v1/counterpartiesbefore requesting a quote. - Provider Requirements satisfied, if the provider needs them. Some providers require KYC or bank details collected against the counterparty before they will price or accept a quote. Check
GET /v1/counterparties/{counterpartyId}/requirements?provider=…&direction=…and submit collected fields withPOSTto the same path untilstatusreadsready. - A custody wallet you control, used as the crypto leg — the onramp destination or the offramp source.
Discovering corridors
GET /v1/payments/ramps/onramp/currency and GET /v1/payments/ramps/offramp/currency list the fiat/crypto pairs SDP supports and which providers cover each one — the Corridor dimensions (currency, country coverage, entity type).
curl "https://api.solana.com/v1/payments/ramps/onramp/currency?source=USD&dest=usdc.solana" \
-H "Authorization: Bearer sk_test_..."| Query param | Notes |
|---|---|
source | Onramp: fiat currency (ISO code). Offramp: crypto rail (usdc.solana, sol.solana, …). |
dest | Onramp: crypto rail. Offramp: fiat currency. |
provider | Narrow to one provider. |
The response's pairs list which providers cover each source/dest combination; providerDetails gives each provider's country coverage and supported entity types for the direction.
Estimating a rate
POST /v1/payments/ramps/onramp/estimate and .../offramp/estimate return a rate preview without creating anything — no counterparty or wallet required. SDP calls every provider on the corridor concurrently and returns one result per provider: ok (with the estimate), unsupported, or error.
curl -X POST https://api.solana.com/v1/payments/ramps/onramp/estimate \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"assetRail": "usdc.solana",
"fiatCurrency": "USD",
"fiatAmount": "100.00"
}'Each entry under estimates carries fiatAmount, cryptoAmount, exchangeRate, and fees when status is ok. Use this to show the user a rate before they commit to a quote.
Requesting a quote
POST /v1/payments/ramps/onramp/quote (fiat → crypto) and POST /v1/payments/ramps/offramp/quote (crypto → fiat) create the actual Ramp Quote against the named provider. This is the step that talks to the provider and, for most providers, produces a provider-side record — unlike estimate, it requires a resolved counterparty and wallet.
curl -X POST https://api.solana.com/v1/payments/ramps/onramp/quote \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"provider": "moonpay",
"counterpartyId": "cp_...",
"destinationWallet": "wal_...",
"cryptoToken": "USDC",
"fiatCurrency": "USD",
"fiatAmount": "100.00"
}'Request fields
| Field | Required | Notes |
|---|---|---|
provider | yes | One of moonpay, lightspark, bvnk, moneygram, coinbase, mural, stripe. |
counterpartyId | yes | An existing Counterparty. Provider-side customer and payout-account state is resolved server-side from it, not passed on the request. Counterparties do not store identity or email fields. |
destinationWallet (onramp) / sourceWallet (offramp) | yes | A custody wallet you control — its walletId or its Solana address, resolved against your API key's wallet scope. Same shape for every provider. |
cryptoToken | yes | Token symbol (USDC, USDT, SOL, …). |
fiatCurrency | onramp: yes; offramp: conditional | Required for onramp and for Lightspark/BVNK offramp; providers that resolve fiat currency during their own flow (MoneyGram) can omit it on offramp. |
fiatAmount (onramp) / cryptoAmount (offramp) | yes | Decimal string greater than zero. |
rampsMemo | no | Up to 20 key/value string pairs stored on the resulting transfer for your own correlation. |
The quote also creates the underlying Payment Transfer record for the ramp; log the returned quote.id (the transfer's providerReference) for your own records.
Delivery mode
quote.deliveryMode tells you how to complete the flow with the named provider:
| Provider | deliveryMode | What to do |
|---|---|---|
| MoonPay | hosted | Redirect the user to quote.hostedUrl. |
| Lightspark | manual_instructions | Display the funding instructions in quote.paymentInstructions (bank or wallet details to send fiat to). |
| BVNK | manual_instructions | Same — display quote.paymentInstructions. |
| MoneyGram | session_widget | Mount quote.widgetUrl using quote.sessionToken. Onramp and offramp both. |
| Coinbase | hosted | Redirect the user to quote.hostedUrl. Onramp only; quote creation is sandbox-only today. |
| Mural | manual_instructions | Display quote.paymentInstructions. Onramp only. |
| Stripe | session_widget | Mount the session with quote.clientSecret and quote.publishableKey. Onramp only. |
There is no further SDP endpoint to call after this — the provider owns settlement from here. Watch for the resulting on-chain transfer on the destination wallet via GET /v1/payments/transfers?direction=inbound, or watch the provider's own side (dashboard or their webhook) for offramp payout confirmation.
Canceling a quote
POST /v1/payments/ramps/transfers/cancel cancels the transfer behind a quote while it is still pending or awaiting_payment — before the provider has moved money.
curl -X POST https://api.solana.com/v1/payments/ramps/transfers/cancel \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"provider": "bvnk",
"providerReference": "..."
}'A transfer past that window (already funded or settling) returns an error instead of canceling.
Status field
quote.status is one of pending, processing, completed, failed, reflecting the provider's reported state at the moment the quote is created — SDP does not subsequently poll the provider to refresh it, and there is no dedicated read endpoint for the quote itself. For the on-chain side of a successful onramp, observe the resulting inbound transfer on the destination wallet, surfaced via Accept payments.
Rate limits
Estimate and quote calls carry fail-closed quotas: estimate fans out one live call per provider on the corridor, quote creates a provider-side record.
| Endpoint | Per-key limit | Per-org limit |
|---|---|---|
.../estimate | 30 / minute | 120 / minute |
.../quote | 20 / minute | 60 / minute |
Provider selection
You always pass provider explicitly; SDP does not auto-select. Choose based on:
- Coverage — which providers your org has Provider Availability for.
- Corridor — currency, country, and entity type; check with the currency-discovery endpoints above.
- Sandbox needs — sandbox vs production is chosen per request from the calling API key's environment (see Sandbox vs production).
Fiat currency support
Fiat currency support is corridor-specific, not a fixed allowlist — use GET /v1/payments/ramps/onramp/currency and .../offramp/currency to see which fiat currencies a given provider covers for a given crypto rail.
Related
- Ramp providers — per-provider configuration and capability matrix.
- Accept overview — how onramp deliveries show up as inbound transfers.
- Provider onboarding — how providers are activated for an organization.