useInitiateFiatRamp hook to launch the same flow with the amount, asset, and provider you choose.
useInitiateFiatRamp requires @getpara/react-sdk 3.18 or later.Which providers, assets, and networks are available — and their API keys — are configured in the Developer Portal, not in code. Set those up first: see Set Up Fiat Onramps (and the Coinbase-specific steps on that page). The hook only launches the flow; it can’t offer a provider or asset you haven’t enabled.
Basic usage
useInitiateFiatRamp returns a mutation-style handle. Call initiateFiatRamp(params) from a click handler to launch the flow:
Choosing the destination wallet
By default the ramp targets the user’s active wallet. Pass a wallet explicitly to target a different one.- Active wallet (default)
- A specific Para wallet
- An external address
Omit the wallet fields — the on-ramp funds whichever wallet is currently active.
Choosing the provider
Omitprovider to let Para pick the first enabled provider that serves the asset + amount, or name one explicitly. Use the OnRampProvider enum:
provider: OnRampProvider.COINBASE and pick the surface with method:
Buying an exact token amount
PasstokenQuantity instead of fiatQuantity to buy a specific amount of the destination token rather than spending a set amount of fiat — useful when the user owes an exact amount (a mint price, a gas top-up, an invoice):
fiatQuantity wins if you pass both. tokenQuantity applies to buys only — it’s ignored for SELL. Para converts the token amount to a fiat estimate at the current rate to check the provider’s minimum and maximum; if that rate lookup fails the amount can’t be validated, so the launch can’t go direct: the prefilled form opens with reason AMOUNT_MISSING (or throws, with throwIfIncomplete: true).Selling (off-ramp)
Passtype: OnRampPurchaseType.SELL to launch a withdrawal instead of a purchase (for providers that support selling — see provider support):
Outcomes
initiateFiatRamp resolves to one of two outcomes:
Failing instead of falling back
PassthrowIfIncomplete: true and the hook throws OnRampLaunchError instead of opening the form. The error carries a machine-readable code alongside a message naming what blocked it:
error off the hook instead of catching, the same as any mutation.
These are the same codes the
form outcome reports as reason, so the handling is identical whichever mode you choose.
Nothing is persisted either way. A purchase row is written only when a purchase actually launches, so a throw leaves nothing behind — and neither does a
form outcome the buyer abandons.Knowing which purchase launched
initiateFiatRamp doesn’t return a purchase id, because when it resolves there may not be a purchase yet: a form outcome means the buyer hasn’t chosen what they’re buying. Purchases also start from the Para Modal’s own Buy button, which never goes through your call at all.
So Para announces the launch as an event. Subscribe once and you’ll see every purchase in your app, whichever surface started it:
onParaEvent returns its own unsubscribe function, so returning it straight from useEffect is all the cleanup you need.
ONRAMP_LAUNCHED fires once per purchase, at the moment the provider session exists and the buyer is paying — the widget popup opening, or the Apple Pay sheet appearing. purchaseId is Para’s id for that purchase: the same id that later arrives on onramp.completed, and the one you pass to getOnRampPurchase.
Because it fires at launch rather than when you called the hook, the payload describes what is actually being bought, after any edits the buyer made in the form. That — not what you asked for — is the purchase to record.
OnRampEventData is the onramp.completed payload field for field, so one function can handle both the browser event and your webhook. Two fields differ by timing rather than design: transactionHash and completedAt are null at launch, because nothing has settled yet.ONRAMP_LAUNCHED and ONRAMP_TRANSACTION_COMPLETE_V2 require @getpara/react-sdk 3.20 or later.Tracking a purchase to completion
A launch is not a delivery. The provider still has to take payment and send the crypto, which happens well after its checkout closes — so follow the purchase by its id rather than treating the launch as the end of the story.1
Subscribe to onramp.completed
Configure a webhook endpoint in the Developer Portal and subscribe to
onramp.completed. It fires once the provider confirms delivery and carries the settlement transaction hash, the delivered token, and the same purchaseId you saw on ONRAMP_LAUNCHED.On your backend, @getpara/rest-sdk exports the payload types. Use ParaWebhookEvent rather than the generic WebhookEvent — it’s a discriminated union, so a switch on event.type narrows event.data to that event’s payload:2
Reconcile anything you missed
Look the purchase up to read its current state — to recover from a dropped webhook, or to check one still in flight:The response is the webhook payload plus a
status of INITIATED, FINISHED, or CANCELLED. transactionHash and completedAt are null until it’s FINISHED, so branch on status rather than inferring completion from the hash, and treat an unrecognized status as non-terminal.The underlying endpoint is GET /v1/onramp/purchases/{purchaseId} if you’d rather call it directly.getOnRampPurchase and the webhook types require @getpara/rest-sdk 3.20 or later. That package is server-side only — it sends your API key on every request, so don’t import it into browser or mobile code.Updating the UI in the browser
For in-app feedback — a toast, a balance refresh — listen forONRAMP_TRANSACTION_COMPLETE_V2, which carries the same OnRampEventData payload with transactionHash and completedAt now filled in:
ONRAMP_LAUNCHED, which fires for every provider, this event depends on the provider telling the browser it settled:
Ramp is the exception. Its widget reports settlement only to Para’s servers and sends nothing back to the browser, so a Ramp purchase reaches you through
onramp.completed alone. Don’t gate a Ramp flow on this event; it will never arrive. You’ll still get ONRAMP_LAUNCHED for the purchase, so you can record the id and wait for the webhook.
ONRAMP_TRANSACTION_COMPLETE (without the _V2) is the older event. It emits the raw purchase row and is skipped entirely for purchases to a raw external address, so prefer _V2 in new code.Test mode
A test purchase runs the real quote and the real provider UI but is never charged — the Apple Pay paths simulate the confirmation instead of taking payment. Test mode routes the purchase to the provider’s own sandbox environment, so you’re exercising their test infrastructure rather than a Para-side simulation: MoonPay and Stripe run against their test keys, and Ramp against its demo environment. Destination networks are swapped for their testnet equivalents too (Ethereum → Sepolia, Solana → Devnet), so use a testnet address or wallet when checking delivery. Where technically possible, every provider honors it; current exceptions include the Coinbase authenticated widget, which always runs against the production widget because Coinbase’s sandbox host doesn’t serve that flow. You rarely need to settestMode yourself; it defaults by environment:
Test purchases still emit
onramp.completed and still appear in the purchase lookup, each flagged with testMode: true. Filter on that field before recording a purchase in production accounting.
Parameters
useInitiateFiatRamp is the low-level entry point behind the Para Modal’s own Buy button, so it works with the same Developer Portal configuration and the same in-modal Buy/Withdraw UI. See initiateOnRampTransaction for the underlying core method.