@ramp-kit/react
v0.1.6
Published
React onramp widget and hooks for LATAM ramps on Stellar: 3-step embeddable flow with live quote countdown, PIX/SPEI deposit instructions and order tracking to settlement, over any @ramp-kit/core provider
Maintainers
Readme
@ramp-kit/react
Drop-in React UI for LATAM fiat on/off-ramps on Stellar. Embeds a complete onramp flow — live quote with countdown, PIX/SPEI deposit instructions, order tracking to settlement — on top of any @ramp-kit/core provider (Etherfuse, Manteca, or the built-in mock).
Install
npm install @ramp-kit/core @ramp-kit/reactReact ≥ 18 is a peer dependency.
<RampWidget />
import { EtherfuseProvider } from "@ramp-kit/core";
import { RampWidget } from "@ramp-kit/react";
const provider = new EtherfuseProvider({ apiKey, environment: "sandbox" });
<RampWidget
provider={provider}
customerId={orgId}
fiatCurrency="BRL"
network="stellar"
walletAddress={userWallet}
assets={await provider.listAssets("stellar", { currency: "brl" })}
onOrderCreated={(id) => console.log("order", id)}
onSettled={(id) => console.log("funds delivered", id)}
/>;The widget walks the user through a 3-step flow:
- Amount — amount + asset selection, live quote with expiry countdown that re-quotes automatically when the provider's price expires.
- Deposit — rail-aware instructions (PIX charge vs. SPEI CLABE) with a live status indicator polled until terminal state.
- Done — conversion summary and on-chain transaction hash.
Props
| Prop | Type | Description |
| --- | --- | --- |
| provider | RampProvider | Any @ramp-kit/core provider instance |
| customerId | string | Provider-side customer id (org UUID for Etherfuse, userAnyId for Manteca) |
| fiatCurrency | "BRL" \| "MXN" \| … | Fiat leg of the ramp |
| direction | "onramp" \| "offramp" | Buy (default) or sell flow |
| network | Network | Settlement network (default "stellar") |
| walletAddress | string? | Destination wallet (onramp) / source wallet (offramp) |
| payoutDestination | { address: string }? | Offramp fiat payout account (CBU/CLABE/IBAN/PIX key). Required for Manteca offramps |
| assets | RampAsset[] | Assets to offer (from provider.listAssets()) |
| signer | (xdr, passphrase) => Promise<string> | Wallet signing callback for offramps (Freighter, hardware, local key) |
| environment | "testnet" \| "mainnet" \| "sandbox" \| "production" | Network the flow runs on. Derives stellarConfig, picks the explorer, and warns on a provider mismatch |
| stellarConfig | StellarConfig | Explicit signing network — overrides environment. Use stellarConfigFor(...) |
| theme | "light" \| "dark" \| RampTheme | Color/radius/font tokens (default "light") |
| size | "sm" \| "md" | Compact or default spacing (default "md") |
| showStepper | boolean | Show the numbered step header (default true) |
| className | string? | Extra class on the root, alongside rk-widget |
| style | CSSProperties? | Inline styles merged onto the root (wins over the theme) |
| labels | Partial<RampLabels> | Override any visible copy (steps, statuses, buttons) — e.g. for i18n |
| locale | string | BCP-47 locale for amount formatting (default "en-US") |
| onOrderCreated | (orderId) => void | Fired when the order is accepted |
| onSettled | (orderId) => void | Fired when funds are delivered |
| onQuote | (quote) => void | Fired whenever a fresh quote arrives |
| onStepChange | (step) => void | Fired when the flow advances between steps |
| onError | (error, context) => void | Fired on any error, tagged "quote" \| "order" \| "sign" |
Theming
Every color, radius and font is a --rk-* CSS variable. Pass a theme preset
or a token set — set only what you want; the rest keep their defaults:
<RampWidget
{...props}
theme={{
background: "#0b1e2d",
surface: "#12293b",
text: "#e6f1f7",
primary: "#38bdf8",
primaryText: "#04222f",
accent: "#34d399",
radius: 16,
}}
/>;theme="dark" ships a full dark palette. You can also override the
--rk-* variables (or the rk-widget / rk-quote / rk-deposit / rk-done
classes) from your own CSS. Translate the copy with labels:
<RampWidget
{...props}
locale="pt-BR"
labels={{
steps: { amount: "Valor", deposit: "Transferência", done: "Pronto" },
youPay: "Você paga",
youReceive: "Você recebe",
continueButton: "Continuar",
}}
/>;Sell flow (offramp) with Freighter
import { signTransaction } from "@stellar/freighter-api";
import { stellarConfigFor } from "@ramp-kit/core";
<RampWidget
provider={provider}
customerId={orgId}
direction="offramp"
fiatCurrency="BRL"
walletAddress={userAddress}
assets={assets}
signer={async (xdr, networkPassphrase) => {
const res = await signTransaction(xdr, { networkPassphrase, address: userAddress });
return res.signedTxXdr;
}}
stellarConfig={stellarConfigFor("sandbox")}
/>;The widget renders an in-widget "Sign & send" step, recovers automatically
from expired provider transactions (tx_too_late → regenerate → re-sign),
and links the settlement transaction on Stellar Expert.
Styling: theme tokens via the theme prop or --rk-* CSS variables, plus
rk- class hooks (rk-widget, rk-quote, rk-deposit, rk-done).
Going to production (testnet → mainnet)
Once you hold production credentials (see the checklist below), flipping to mainnet is a single value used in two places — the provider and the widget:
import { EtherfuseProvider } from "@ramp-kit/core";
// One flag drives everything. "production" and "mainnet" are equivalent here.
const environment = "production";
const provider = new EtherfuseProvider({
apiKey: process.env.ETHERFUSE_API_KEY!, // production key
environment, // flips the API base URL to mainnet
baseUrl: "https://api.myapp.com/ramp/etherfuse", // your @ramp-kit/server
});
<RampWidget
provider={provider}
environment={environment} // derives mainnet Horizon + passphrase + explorer
customerId={realCustomerId}
fiatCurrency="BRL"
walletAddress={userWallet}
assets={await provider.listAssets("stellar")}
/>;Pass the same environment to the provider and the widget. If they differ,
the widget logs a console warning so a testnet UI never signs against mainnet
funds by accident. Omit environment and it stays on testnet (default).
The switch is code; it doesn't create the credentials. Working on mainnet also requires, per provider (one-time, outside the SDK):
- Etherfuse: production KYB approval →
api_prod_…key; real registered bank accounts (real CLABE/RFC/PIX); real end-user KYC (no sandbox auto-approve). - Manteca: commercial onboarding → production
md-api-key, per-country permissions, real onboarded users. - Stellar: the wallet must be on the Public network with real XLM for fees and reserves. The kit already prices fees dynamically and fee-bumps under congestion, so mainnet submission is handled.
Full operational checklist: skills/ramp-kit/references/production.md in the repo.
Hooks (build your own UI)
import { useQuote, useOrder } from "@ramp-kit/react";
// Live quote that refreshes itself when it expires
const { quote, loading, error, secondsLeft, refresh } = useQuote(provider, {
direction: "onramp",
fiatCurrency: "BRL",
assetIdentifier: usdc.identifier,
network: "stellar",
sourceAmount: "100",
customerId,
});
// Order polling that stops at settled/failed/cancelled
const { order, polling } = useOrder(provider, orderId);Instant development with the mock provider
import { MockProvider } from "@ramp-kit/core";
// Realistic lifecycle without credentials; auto-funds orders after 4s
const provider = new MockProvider({ autoFundMs: 4000 });Two demo apps (a full sandbox demo on Stellar Testnet and a second minimal integration) live in the latam-ramp-kit repository.
AI tooling
Building this integration with an AI coding agent? Install the kit's agent
skill (npx skills add https://github.com/armandocodecr/latam-ramp-kit/tree/main/skills/ramp-kit)
and the @ramp-kit/mcp MCP
server — the agent gets integration knowledge, verified troubleshooting,
and live tools to quote and test orders against the sandbox.
MIT © Armando Cruz
