{
  "markdown": "# LATAM Ramp Kit\n\n[![CI](https://github.com/armandocodecr/latam-ramp-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/armandocodecr/latam-ramp-kit/actions/workflows/ci.yml)\n[![npm: core](https://img.shields.io/npm/v/%40ramp-kit%2Fcore?label=%40ramp-kit%2Fcore)](https://www.npmjs.com/package/@ramp-kit/core)\n[![npm: react](https://img.shields.io/npm/v/%40ramp-kit%2Freact?label=%40ramp-kit%2Freact)](https://www.npmjs.com/package/@ramp-kit/react)\n[![npm: server](https://img.shields.io/npm/v/%40ramp-kit%2Fserver?label=%40ramp-kit%2Fserver)](https://www.npmjs.com/package/@ramp-kit/server)\n[![npm: mcp](https://img.shields.io/npm/v/%40ramp-kit%2Fmcp?label=%40ramp-kit%2Fmcp)](https://www.npmjs.com/package/@ramp-kit/mcp)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.armandocodecr%2Framp--kit-blue)](https://registry.modelcontextprotocol.io/?search=io.github.armandocodecr/ramp-kit)\n[![license: MIT](https://img.shields.io/badge/license-MIT-green)](./LICENSE)\n\nDrop-in SDK + React components to add fiat on/off-ramps to any app in Latin\nAmerica, built for the Stellar **Brazil Ramps and Regional Kits** sub-lane.\n\n## Install\n\n```bash\nnpm install @ramp-kit/core @ramp-kit/react   # SDK + React widget\nnpm install @ramp-kit/server                 # production backend (optional)\n```\n\nFor AI agents:\n\n```bash\nclaude mcp add ramp-kit -- npx -y @ramp-kit/mcp                                          # MCP server\nnpx skills add https://github.com/armandocodecr/latam-ramp-kit/tree/main/skills/ramp-kit # agent skill\n```\n\n**BRL in *and* out, proven on Stellar Testnet (Etherfuse sandbox):**\n\n- **In:** 100 BRL entered via PIX and settled as 19.0097 USDC in a fresh\n  Stellar wallet — account creation sponsored by the provider, tokens\n  delivered via claimable balance, claimed with one kit helper.\n  [Settlement tx on Stellar Expert.](https://stellar.expert/explorer/testnet/tx/95b4e01c139330fecfa9861d8a88735eec29433cdd5d6e7a67b2aaada98e00f4)\n- **Out:** 5 USDC sold back to BRL — the provider pre-built the burn\n  transaction, the kit's `signAndSubmit` signed and submitted it\n  ([burn tx](https://stellar.expert/explorer/testnet/tx/5bfc0470735be2a629870747e52edf429b3727d001f3721ee77a87f11f76cb6f)),\n  and the PIX payout processed provider-side. The widget ships the full\n  Sell flow with in-widget signing and automatic `tx_too_late` recovery.\n\nOne provider interface, two direct backends plus **any SEP-compliant Stellar\nanchor** (and a mock for instant dev):\n\n| Provider | Rails | Networks | Role in the kit |\n| --- | --- | --- | --- |\n| [Etherfuse](https://docs.etherfuse.com) | **BRL (PIX)** + MXN (SPEI) | **Stellar** (native), Solana, Base, Polygon | Stellar-native settlement: automatic trustlines, sponsored onboarding via claimable balances |\n| [Manteca](https://docs.manteca.dev/cripto) | **In:** BRL (PIX), ARS, MXN, CLP · **Out:** those + COP, PEN, GTQ, CRC, BOB, PUSD, PHP | **Stellar**, EVM chains, Tron | Broadest LATAM payout coverage — 11 countries — behind the same interface. **Verified live**: BRL→PIX→USDC delivered on Stellar Testnet |\n| `SepProvider` | any the anchor serves | **Stellar** | Fronts **any SEP-compliant anchor** (SEP-1/10/38/24): the end user authenticates with their own wallet, no partner key. One adapter, the whole anchor ecosystem |\n| `MockProvider` | any | Stellar | Instant local dev + integration tests, realistic order lifecycle |\n\n```tsx\nimport { EtherfuseProvider } from \"@ramp-kit/core\";\nimport { RampWidget } from \"@ramp-kit/react\";\n\nconst provider = new EtherfuseProvider({ apiKey });\nprovider.setBankAccount((await provider.listBankAccounts())[0].bankAccountId);\n\n<RampWidget\n  provider={provider}\n  customerId={orgId}\n  fiatCurrency=\"BRL\"\n  network=\"stellar\"\n  assets={await provider.listAssets(\"stellar\", { currency: \"brl\" })}\n/>;\n```\n\nSwapping providers is one line (`new MantecaProvider({ apiKey })`,\n`new MockProvider()`), or let the router pick per country and compare live\nquotes:\n\n```ts\nconst router = new RampRouter()\n  .register(new EtherfuseProvider({ apiKey }))\n  .register(new MantecaProvider({ apiKey: mantecaKey }));\n\n// Routing is direction-aware: Manteca pays out across 11 countries but only\n// takes deposits in 4, so the same corridor can resolve differently.\nconst provider = router.resolve({\n  country: \"CO\",\n  fiatCurrency: \"COP\",\n  direction: \"offramp\",\n});\nconst quotes = await router.compareQuotes(request, { fiatCurrency: \"BRL\" });\n```\n\n## Packages\n\n- **`@ramp-kit/core`** — framework-agnostic TypeScript SDK\n  - `RampProvider` interface: `listAssets` → `getQuote` → `createOrder` → `getOrder`\n  - Normalized order lifecycle: `created → awaiting_deposit → awaiting_signature → processing → settled | failed | cancelled`\n  - `EtherfuseProvider` (incl. `registerWallet`, `listBankAccounts`,\n    sandbox `simulateFiatReceived`), `MantecaProvider`, `MockProvider`\n  - `RampRouter`: provider selection per country/currency + live quote comparison\n  - Stellar helpers: `getAccountState` (trustline/reserve checks),\n    `getPendingBalances` / `claimPendingBalances` (sponsored-onramp claims),\n    `signAndSubmit` (handles `tx_too_late` → regenerate), `parseAssetIdentifier`\n- **`@ramp-kit/react`** — `<RampWidget />` embeddable stepper flow (live quote\n  countdown, PIX/SPEI deposit instructions, status tracking), `useQuote`\n  (auto-refresh on expiry), `useOrder` (polls until terminal state)\n- **`@ramp-kit/server`** — zero-dependency production backend: API-key proxy\n  with a strict endpoint allowlist, plus webhook receivers with HMAC-SHA256\n  signature verification (RFC 8785 canonicalization for Etherfuse)\n- **`apps/demo`** — full BRL·PIX / MXN·SPEI onramp on Stellar Testnet:\n  built-in test wallet, live Horizon balance panel, one-click claim\n- **`apps/second-app`** — the same widget dropped into a different app\n  (the sub-lane's \"works in a second app\" criterion)\n\n## Why two providers\n\nManteca has the broadest LATAM fiat rails; Etherfuse is Stellar-native with\nsponsored wallet onboarding. Both settle USDC on Stellar (Manteca added\nStellar support recently — verified live by this kit), which makes real\nmulti-anchor comparison possible on the same corridor:\n`RampRouter.compareQuotes` fans one request out to both and returns live\nrates sorted (verified: 100 BRL → 19.49 USDC Etherfuse vs 19.23 USDC Manteca).\nThey still expose completely different mental models (quote/order vs.\nmulti-stage synthetics + price locks) — the kit hides that behind one\ninterface, which is exactly the pain an app integrating ramps in the region\nhits first.\n\n| | Etherfuse | Manteca | Kit exposes |\n| --- | --- | --- | --- |\n| Pricing | quote (2 min expiry) | price lock (`expireAt`) | `RampQuote.expiresAt` + auto-refresh |\n| Execution | order | ramp synthetic (stages) | `RampOrder.status` (one lifecycle) |\n| Deposit info | CLABE / PIX charge on order | `details.depositAddress` | `DepositInstructions` |\n| Stellar | trustlines, claimable balances, tx expiry | — | `stellar.ts` helpers |\n\n## Running the demo (100% sandbox, no real money)\n\n```bash\npnpm install\npnpm dev        # demo on http://localhost:5173\n```\n\n**Zero-setup path:** pick \"Mock provider\" and walk the full flow immediately.\n\n**Real sandbox path (Stellar Testnet):**\n\n1. Create a sandbox account at <https://sandbox.etherfuse.com> — approve your\n   own KYB with the sandbox button.\n2. In the dashboard, use **Add BRL Bank Account (PIX)** — it comes pre-filled\n   with test values and is compliant instantly. (MXN accounts registered via\n   API await async approval.)\n3. Copy your `api_sand…` key into the demo and **connect Freighter** (your\n   own wallet signs everything — or generate a throwaway test wallet; the\n   provider registration happens automatically). Run an onramp: quote →\n   order → simulate the incoming PIX → watch it settle on Stellar Testnet →\n   claim the delivered claimable balance with one click. Then flip to\n   **Sell** to go the other way: USDC → BRL with in-wallet signing, both\n   transactions linked to Stellar Expert for public verification.\n\nManteca sandbox (`https://sandbox.manteca.dev/crypto/v2`) requires credentials\nfrom the Manteca team; the adapter is implemented from their public docs and\nships with the same normalized lifecycle.\n\n> **Note on API keys:** a provider key identifies your *business* (its KYB,\n> fees and settlement accounts) — there is one per app, held server-side, and\n> end users never see it. They are customers under it, identified by\n> `customerId`. The demo asks you to paste a key only because whoever opens\n> it is playing the role of the integrating developer.\n\n## Shipping it to your own users\n\nYou get partner keys from Etherfuse and/or Manteca once. Your users just\nclick buy — they never see a key or an API.\n\n```\nbrowser (no key)  →  your backend (keys in env)  →  Etherfuse / Manteca\n   <RampWidget/>       @ramp-kit/server\n```\n\n```ts\n// your backend — the only place keys exist\ncreateRampServer({\n  proxy:   { apiKey: process.env.ETHERFUSE_API_KEY!, environment: \"production\" },\n  manteca: { apiKey: process.env.MANTECA_API_KEY!,   environment: \"production\" },\n}).listen(8787);\n\n// your frontend — empty key, pointed at your backend\nnew EtherfuseProvider({ apiKey: \"\", baseUrl: \"https://api.myapp.com/ramp/etherfuse\" });\n```\n\nRunnable in [examples/backend-integration](examples/backend-integration) —\nverified end to end against the real sandboxes with an empty client key:\nquote → order → deposit → `settled`, while privileged endpoints (user\nonboarding, company config, accounting) return `403` through the proxy.\n\nThe one piece that stays yours: onboarding each user with the provider\n(KYC) to get their `customerId`. That's inherent to operating a ramp — from\nquote onward the kit handles it.\n\n**Why a backend at all?** Frontend env vars (`VITE_*`, `NEXT_PUBLIC_*`) are\nembedded in the served JS bundle — any visitor can read them, so a partner\nkey there is exposed. The key must live in a backend env var behind\n`@ramp-kit/server` (a ~10-line serverless function, not real\ninfrastructure). The exception is the SEP-anchor route: `SepProvider` needs\nno partner key — the end user authenticates with their own wallet — so it\nruns entirely in the frontend.\n\nFull step-by-step for **testnet and mainnet** (env files, the single\n`RAMP_ENV` flag, wallet networks, credential checklists):\n[skills/ramp-kit/references/environments.md](skills/ramp-kit/references/environments.md).\nThe same guide ships inside the AI tooling — agents with the kit's skill or\nthe `@ramp-kit/mcp` server (`get_documentation` → `environments`) can walk\nyou through it.\n\n## Deploy the demo (Vercel)\n\nThe demo ships ready to deploy — a serverless proxy at `api/[...path].ts`\n(auto-detected by Vercel at the repo root):\n\n1. [vercel.com/new](https://vercel.com/new) → import\n   `armandocodecr/latam-ramp-kit`.\n2. **Root Directory:** `./` · **Framework Preset:** Other, with three\n   overrides in Build & Development Settings:\n   - Install Command: `pnpm install`\n   - Build Command: `pnpm -r build`\n   - Output Directory: `apps/demo/dist`\n3. Deploy. **No environment variables are needed.**\n\nWhat the deployed demo does:\n\n- **Mock provider works for everyone**, with zero setup — the full widget\n  flow, buy and sell.\n- **Live sandbox modes relay the visitor's own key**: the browser calls\n  `/api/<provider>/*`, the function forwards it to the provider with the\n  same endpoint allowlist `@ramp-kit/server` enforces. The deployment holds\n  no credentials and stores nothing.\n- Upstreams are pinned to the providers' **sandbox** hosts, so a deployed\n  demo can never reach production money.\n\n## Field notes (verified against the real sandbox)\n\n- `GET /ramp/assets` requires `blockchain`, `currency` and `wallet` — the kit\n  fills sensible defaults.\n- Bring-your-own wallets must be registered before their first order — the\n  SDK **self-heals** this: `createOrder` registers (idempotent) and retries\n  on \"Wallet not found\". `claimOwnership: true` under a KYB-approved org\n  marks wallets compliant with no per-wallet KYC.\n- PIX onramp orders report `depositBankName: \"PIX\"` with an empty CLABE — the\n  kit maps this to a PIX `DepositInstructions` automatically.\n- First-time wallets receive tokens as **claimable balances** (plus ~1.5 XLM\n  sponsored reserves); `claimPendingBalances` builds trustline + claim in one\n  transaction.\n\n## AI tooling: MCP server + agent skill\n\nThe kit ships first-class AI support — both for **understanding** it and for\n**operating** it. An AI agent has already driven the full flow through these\ntools: quoted 50 BRL → USDC, created the sandbox order, simulated the PIX\npayment and watched it settle on Stellar Testnet.\n\n- **[@ramp-kit/mcp](packages/mcp)** — MCP server published on\n  [npm](https://www.npmjs.com/package/@ramp-kit/mcp) and listed in the\n  [official MCP Registry](https://registry.modelcontextprotocol.io/?search=io.github.armandocodecr/ramp-kit)\n  as `io.github.armandocodecr/ramp-kit`. Nine tools: built-in documentation\n  (`get_documentation` with 6 topics), provider discovery, live quotes,\n  multi-provider comparison, sandbox orders, deposit simulation\n  (sandbox-only by design) and Stellar wallet inspection. Works\n  credential-free with the mock provider.\n\n  ```bash\n  claude mcp add ramp-kit -e ETHERFUSE_API_KEY=api_sand_… -- npx -y @ramp-kit/mcp\n  ```\n\n  Or in any MCP client's `mcpServers` config:\n\n  ```json\n  { \"ramp-kit\": { \"command\": \"npx\", \"args\": [\"-y\", \"@ramp-kit/mcp\"] } }\n  ```\n\n- **[skills/ramp-kit](skills/ramp-kit)** — agent skill (Claude Code, Cursor,\n  and any agent supported by the [skills CLI](https://skills.sh)): teaches\n  the agent what the kit solves, the integration flow, sandbox setup,\n  verified troubleshooting and the production checklist.\n\n  ```bash\n  npx skills add https://github.com/armandocodecr/latam-ramp-kit/tree/main/skills/ramp-kit\n  ```\n\nTogether they cover both halves: the skill gives an agent the **knowledge**\nto guide an integration; the MCP server gives it **hands** to actually\nquote, order and verify against the sandbox. This pairs naturally with\nStellar's agentic-payments direction (x402/MPP): a ramp that AI agents can\nunderstand and operate end-to-end.\n\n## Path to production\n\nThe code is production-ready; what remains is provider onboarding. Ready today:\n\n- **Environment switch** — `environment: \"sandbox\" | \"production\"` on every\n  provider flips base URLs; `stellarConfigFor(\"production\")` returns mainnet\n  Horizon + network passphrase. No hardcoded issuers anywhere: assets are\n  always discovered via the provider, so mainnet identifiers flow through\n  automatically.\n- **Server-side key handling** — `@ramp-kit/server` ships `createRampServer`:\n  the API key lives in your backend, the browser only reaches an allowlisted\n  ramp surface (quote/order/status), and the sandbox simulation endpoint is\n  hard-blocked in production.\n- **Webhooks over polling** — `createEtherfuseWebhookHandler` verifies\n  `X-Signature` (HMAC-SHA256 over RFC 8785-canonicalized JSON, constant-time\n  compare), acks 2xx immediately, and dispatches typed events.\n  `verifyMantecaSignature` covers Manteca's shared-secret HMAC.\n- **Real wallets** — signing is callback-based (`claimPendingBalances`,\n  `signAndSubmit`), so Freighter/hardware wallets plug in directly. The\n  demo's localStorage keypair is a sandbox convenience, not the pattern.\n- **Sandbox-only code is fenced** — `simulateFiatReceived` throws in\n  production; deposits are detected from the real SPEI/PIX transfer.\n\nExternal steps (with the provider, not in code):\n\n1. **Etherfuse production KYB** — real legal-entity review (manual, allow\n   days/weeks), then an `api_prod_…` key. Register real bank accounts (real\n   CLABE/RFC) and confirm **BRL/PIX production availability** (live in\n   sandbox; listed as upcoming for production).\n2. **End-user KYC** — production users complete the hosted identity flow\n   (documents + liveness); sandbox auto-approval does not apply.\n3. **Manteca credentials** — commercial onboarding for a production\n   `md-api-key`, per-country permissions (BRL/PIX), and webhook secret;\n   confirm their signature header name during onboarding.\n4. **Deploy `@ramp-kit/server`** behind HTTPS, register the webhook URL via\n   `POST /ramp/webhook`, and store the one-time secret.\n5. **Persistence** — store quote/order idempotency UUIDs and webhook events\n   (dedupe by resource id + status) in your database.\n\n## Repo layout\n\n```\npackages/core    @ramp-kit/core   — SDK, adapters, router, Stellar helpers\npackages/react   @ramp-kit/react  — widget + hooks\npackages/server  @ramp-kit/server — production proxy + webhook verification\npackages/mcp     @ramp-kit/mcp    — MCP server for AI agents (official MCP Registry)\napi/             serverless ramp proxy for the deployed demo (Vercel)\nskills/ramp-kit  agent skill      — integration knowledge for AI coding agents\nexamples/agent-checkout — third-party checkout using only the published npm artifacts\napps/demo        primary demo (Etherfuse sandbox / mock, Stellar Testnet)\napps/second-app  second integration of the same widget\ndocs/            provider research + Etherfuse OpenAPI spec\n```\n",
  "bytes": 17150,
  "sha": "d2f8d89bdbdb6654c29b257e46e311c93f0df7e398a3bb7b04b845be582e4bd9",
  "repo_slug": "armandocodecr/latam-ramp-kit",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_armandocodecr_ramp_kit_1de23142/readme"
}