Skip to main content
Base mainnet / viem 2.x / non-custodial

USDC-to-fiat in one SDK call.

offramp() creates the deposit, delegates pricing to the managed vault, and returns a deposit ID. Your users settle on Venmo, Revolut, Wise, Cashapp, Zelle, Monzo, or PayPal without leaving your app.

Webhook delivery~60sUp to 5 retries, HMAC-signed

Agent bundle

Point your agent at these.

Drop the skill into Claude Code or Codex, hand llms-full.txt to any assistant, or scaffold a working app from a starter. Every artifact is machine-readable.

Flow

What the SDK handles.

Validate01

Collect payout details

Validate amount, platform, currency, and payout identifier before the wallet prompt.

PLATFORMS.*.validate()
Sign02

Create the deposit

offramp() registers the payout route, approves USDC, and creates the escrow deposit on Base.

offramp(walletClient, params)
Delegate03

Hand off pricing

Fresh deposits delegate to the managed vault for rate updates. Your backend does not quote.

rateManagerId
Sync04

Watch settlement

Use signed webhooks or deposits() to sync fills, closes, and OTC taker activity.

deposit.filled

First call

One signature, four runtimes.

Pass an idempotencyKey for retrying jobs. Reusing the same key returns the original result instead of creating a duplicate deposit.

import { useOfframp } from "@usdctofiat/offramp/react";
import { CURRENCIES, PLATFORMS } from "@usdctofiat/offramp";

function SellButton({ walletClient }) {
  const { offramp, step, isLoading } = useOfframp({
    integratorId: "your-app",
    referralId: "partner-123",
  });

  return (
    <button
      disabled={isLoading}
      onClick={() =>
        offramp(walletClient, {
          amount: "100",
          platform: PLATFORMS.VENMO,
          currency: CURRENCIES.USD,
          identifier: "alice",
        })
      }
    >
      {isLoading ? step ?? "Working..." : "Sell 100 USDC"}
    </button>
  );
}
ResultConfirmed on Base
depositId0xfa3c...b8821
txHash0x1f4a90b2...d04e
resumedfalse
otcLinknull for public deposits

OTC deposits return a shareable otc.usdctofiat.xyz/d/... link for the approved buyer.

Boundaries

Know what you own.

Keys

Your WalletClient signs

The SDK holds no keys. User wallets and server wallets sign through your viem WalletClient.

Fiat

P2P payout rails stay direct

Buyers pay sellers on Venmo, Revolut, Wise, Cashapp, Zelle, Monzo, or PayPal. The SDK does not route fiat.

Rates

Pricing is delegated

Deposits delegate to the managed vault, so you do not run oracle wiring, quote jobs, or rate crons.

Scaffold

Start with a working wallet flow.

Three templates ship with create-offramp-app. Replace TODO_SET_REFERRAL_ID before shipping partner attribution. Reference scripts and the live demo source live in the starters repo.

--template=nextNext.js + PrivyApp Router, wallet client, sell button, deposit list. Production-shaped.
--template=viteVite + ReactSPA template with the same SDK call and fewer moving parts.
--template=telegram-botTelegram botServer-side maker flow with a managed wallet client (grammy + viem).

Webhooks

Signed lifecycle events.

Register endpoints and rotate signing secrets at peerlytics.xyz/developers — same API key, both products. Every delivery includes X-Usdctofiat-Signature, X-Usdctofiat-Event, and X-Usdctofiat-Delivery-Id. Verify the raw body before JSON parsing.

POST your endpointX-Usdctofiat-Event: deposit.createdX-Usdctofiat-Signature: t=1745392504,v1=8a1c...b9f2X-Usdctofiat-Delivery-Id: 5b1a3f2c-9ad8-4f0a-8c03

Selected event

deposit.created

A deposit landed on Base. Use it to create internal inventory records.

Register at Peerlytics

Ship the first deposit.

Read the API reference for signatures, then mint an API key on Peerlytics when you need webhooks or paid analytics.