buy or sell
order you send, not by the route, so the two cannot disagree. Assets are Solana
only.
Auth
Use an API key:Routes
Configuration fields
The options, quotes, and order-creation routes require both fields below.
On the options route these are query parameters; on the quote and order routes
they are body fields. Order reads and transfer actions identify the stored
order in the route path and require neither field.
The provider environment is not a Solana cluster. A sandbox order still settles
on mainnet.
Amounts
Amounts are unsigned integers in the smallest unit the thing has, encoded as decimal strings:
An amount finer than the currency’s minor unit is refused, never rounded. Read
AssetOption.decimals and FiatCurrencyOption.exponent from the options route
to build a valid value.
A crypto asset is one of two shapes. Native SOL carries no mint:
exchangeRate is the one decimal string that is not an integer: a rate is a
ratio and has no minor unit to scale to. It is display-only.
Get options
GET /wallet/api/ramp/options
Query parameters:
Response fields:
decimals is Swig’s own value for the asset, not the provider’s.
Get quotes
POST /wallet/api/ramp/quotes
sell instead of buy for the other direction:
quotes, each with a route of provider and
paymentMethod, plus a buy or sell arm holding the priced amounts, the
totalFee, and the exchangeRate.
Create an order
POST /wallet/api/ramp/orders
requestId is your idempotency key and is unique within the configuration.
Repeating it returns the stored order; repeating it with different inputs is
refused with ALREADY_EXISTS. Mint it before the first attempt and reuse it
across retries.
The response is { "order": ... }. An order carries id, status,
createdAt, updatedAt, and a buy or sell detail arm.
Read an order
GET /wallet/api/ramp/orders/{order_id}
Returns { "order": ... }. A read of a non-final order refetches the provider’s
record first, so polling this route is what advances the order and fills in the
deposit address a sell needs.
A buy carries the quote and an optional
launchUrl. A sell also carries
deposit once the provider assigns one, and transfer once one is prepared.
A transfer.state is TRANSFER_STATE_UNSPECIFIED, PREPARED, SUBMITTED,
LANDED, FAILED, or EXPIRED. A transfer settles only at confirmed or
better, so a processed signature still reads as in-flight, and a read of the
order does not advance it — only submission resolves an attempt.
Prepare a transfer
POST /wallet/api/ramp/orders/{order_id}/transfer/prepare
Sell only, and refused with FAILED_PRECONDITION unless every condition holds:
the order is unfinished, it is a sell (only a sell needs a transfer), its
network is mainnet (ramp transfers settle on mainnet only), it carries a
deposit (the deposit address is not ready), and no other attempt is live
(a transfer for this order is already in progress). The provider assigns the
deposit while the customer is in the order’s checkout, so poll the order until
it reaches AWAITING_TRANSFER and carries one.
{ "preparedTransfer": ... }, carrying the transfer, the
preparedTransaction to sign, and the canonical deposit. The transfer is
built from the provider’s own record rather than the quote, so a repriced amount
funds the deposit correctly. transfer.expiresAt is the prepared blockhash’s
lifetime.
Submit a transfer
POST /wallet/api/ramp/orders/{order_id}/transfer/submit
{ "transfer": ... } with a state of
TRANSFER_STATE_LANDED and the solanaSignature that landed. The route waits
for confirmed or better, so it does not return a pending transfer: every
other outcome is an error, and the error is what tells you which attempt you
still own.
The prepared transaction is handed over exactly once. If you broadcast it and
then lose it, submit again with an empty
signedTransaction to resolve the
attempt that is already live; resolution is answered from the stored attempt,
so it does not need the bytes you lost.
Retain the order and transfer ids until an attempt reaches a settled state.
Reading the order reconciles it against the provider but does not resolve the
transfer’s chain state, so an attempt that was submitted and never resolved
stays SUBMITTED and keeps the order’s one live transfer slot. Prepare a
replacement only after the previous attempt has been reported as failed —
never in response to a confirmation timeout.
Errors
Validation failures returnINVALID_ARGUMENT. A configuration that is disabled
or not approved returns FAILED_PRECONDITION, and that stops orders already in
flight, not only new ones. See Errors.
SDK equivalent
The Developer SDK wraps these routes asswig.ramp in
TypeScript and Python.
