Integrate Frax Ramp
There are two ways to drop the on- and off-ramp into your app. Use the React package for React apps, or the hosted iframe for everything else. Both talk to the same hosted API — no registration or secrets required.
React package
Install the package and import its stylesheet once (e.g. in your root layout):
pnpm add @iqai/ramp-react
Render the widget with a destination address to let users buy frxUSD with fiat:
import '@iqai/ramp-react/styles.css';
import { CRYPTO_ASSET, FIAT_CURRENCY, FraxRampWidget } from '@iqai/ramp-react';
export function Checkout({ wallet }) {
return (
<FraxRampWidget
destinationAddress={wallet.address}
amount={100}
fiatCurrency={FIAT_CURRENCY.USD}
cryptoAsset={CRYPTO_ASSET.FRXUSD}
/>
);
}
To let users sell frxUSD for a fiat payout, optionally pass an onSellDeposit callback. When present, a "Send with wallet" button appears that hands you the deposit details so you can move the tokens and return the transaction hash. If you omit it, the widget falls back to the manual path — the user sends the tokens themselves and pastes the tx hash.
<FraxRampWidget
fiatCurrency={FIAT_CURRENCY.USD}
cryptoAsset={CRYPTO_ASSET.FRXUSD}
onSellDeposit={async ({ amount, receiver, token }) => {
const txHash = await wallet.sendErc20(token, receiver, amount);
return { txHash };
}}
/>
Key props
| Prop | Type | Description |
|---|---|---|
destinationAddress | string | Wallet that receives crypto on a buy. |
amount | number | Prefilled amount. |
fiatCurrency | FiatCurrency | Fiat side, e.g. FIAT_CURRENCY.USD. |
cryptoAsset | CryptoAsset | Crypto side, e.g. CRYPTO_ASSET.FRXUSD. |
defaultSide | 'BUY' | 'SELL' | Which direction the widget opens on. |
appearance | 'light' | 'dark' | 'system' | Theme. Defaults to system. |
inheritShadcn | boolean | Inherit your app's shadcn theme tokens. |
onSellDeposit | function | Called on a sell; send the tokens and return { txHash }. |
onOrderStatusChange | function | Receives the latest order status. |
onOrderCreated | function | Fires once when an order is created — { side, order }. |
onError | function | Fires on a recoverable flow error — { side, message }. |
Hosted iframe
For non-React apps, embed the hosted widget and configure it through query params. Pass parentOrigin so the iframe can post events back to your page:
<iframe
id="frax-ramp"
src="https://fraxramp.com/embed?cryptoAsset=FRXUSD&fiatCurrency=USD&parentOrigin=https%3A%2F%2Fapp.example.com"
style="width: 420px; height: 640px; border: 0"
></iframe>
Query params
| Param | Description |
|---|---|
cryptoAsset | Crypto asset, e.g. FRXUSD. |
fiatCurrency | Fiat currency, e.g. USD. |
amount | Prefilled amount. |
defaultSide | BUY or SELL. |
destinationAddress | Destination wallet for a buy. |
appearance | light, dark, or system. |
parentOrigin | Your app's origin, required to receive events. |
Selling through the iframe
To open the sell flow, set defaultSide=SELL. Because you can't pass a function across the iframe boundary, the React onSellDeposit callback is bridged over postMessage:
- When the user reaches the deposit step, the iframe emits a
sell_deposit_requestedevent carrying arequestIdand the depositrequest(amount,receiver,token,chainId). - Your page moves the tokens with its own wallet and posts a
sell_deposit_resultmessage back into the iframe with the matchingrequestIdand the resultingtxHash(or anerror). - The widget confirms the deposit and moves on.
const iframe = document.getElementById('frax-ramp');
window.addEventListener('message', async (event) => {
if (event.origin !== 'https://fraxramp.com') return;
if (event.data?.source !== 'frax-ramp') return;
if (event.data.type !== 'sell_deposit_requested') return;
const { requestId, request } = event.data;
try {
const txHash = await wallet.sendErc20(request.token, request.receiver, request.amount);
iframe.contentWindow.postMessage(
{ source: 'frax-ramp-host', version: 1, type: 'sell_deposit_result', requestId, txHash },
'https://fraxramp.com'
);
} catch (err) {
iframe.contentWindow.postMessage(
{ source: 'frax-ramp-host', version: 1, type: 'sell_deposit_result', requestId, error: String(err) },
'https://fraxramp.com'
);
}
});
If you don't handle the event, the user can still complete the sell manually — the widget always shows a deposit address and a field to paste the transaction hash.
Listening for events
The iframe posts messages to your page. Every event carries source: 'frax-ramp' and version: 1. Always verify the origin and the source field before trusting an event:
window.addEventListener('message', (event) => {
if (event.origin !== 'https://fraxramp.com') return;
if (event.data?.source !== 'frax-ramp') return;
switch (event.data.type) {
case 'ready':
// widget mounted
break;
case 'resize':
// event.data.height — adjust the iframe height
break;
case 'order_created':
// event.data.side, event.data.order (orderId, redirect / deposit details)
break;
case 'order_status_changed':
console.log(event.data.status);
break;
case 'error':
console.warn(event.data.side, event.data.message);
break;
}
});
Event type | Payload | Description |
|---|---|---|
ready | — | Widget has mounted and is ready. |
resize | height | New content height in pixels. |
order_created | side, order | An order was created (before funding). Buy carries providerRedirectUrl; sell carries the deposit details. |
order_status_changed | status | Latest order status object. |
error | side, message | A recoverable error surfaced in the flow. |
sell_deposit_requested | requestId, request | Host should send the tokens and post back a sell_deposit_result. |
REST API
Both integrations sit on top of a plain REST API. For the full endpoint reference, see the API reference.