> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pods.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Pods Ramp (Fiat On/Off-Ramp)

> Pix on/off-ramp and foreign USD ACH/WIRE onramp using the one-call quote flow

This example demonstrates fiat on/off-ramp with Pods Ramp using the Pods API. Every route uses
`GET /v2/swap/quote`: `originChain`/`destinationChain` of `fiat` select the local rail, and
`tokenIn`/`tokenOut` select the fiat currency or on-chain asset.

<Info>
  Money-movement routes are available only after the wallet's Ramp KYC profile is `approved`. See
  the [KYC backend example](/examples/javascript/kyc-backend) and
  [Set up Pods Ramp](/guides/ramp/setup).
</Info>

## Overview

This example covers:

* **Pix onramp** — Pix BRL → USDC (show the Pix code, then poll)
* **Pix offramp** — USDC → Pix BRL (sign `transactionData`, then poll)
* **Foreign USD onramp** — USD ACH/WIRE → USDC (show bank details, then poll)

## Prerequisites

* Node.js 18+
* Pods API key
* A wallet with an `approved` Ramp KYC profile (offramp additionally requires the signer key)

## Installation

```bash theme={null}
npm install axios viem
```

## Environment Variables

```bash theme={null}
PODS_API_KEY=your-api-key
WALLET_ADDRESS=0x...            # user wallet receiving crypto (onramps)
PRIVATE_KEY=0x...               # signer for offramps (approved Ramp wallet)
BASE_RPC_URL=https://base-mainnet.g.alchemy.com/v2/your-key
PIX_KEY=user-pix-key@example.com
```

<Warning>
  Send all requests from your **backend**. Never expose `PODS_API_KEY` in a browser or mobile client.
</Warning>

## Step-by-Step Walkthrough

### 1. Initialize API Client

```javascript theme={null}
import axios from 'axios'

const pods = axios.create({
  baseURL: 'https://api.pods.finance',
  headers: {
    'x-api-key': process.env.PODS_API_KEY,
    'Content-Type': 'application/json'
  }
})

const TERMINAL = ['fulfilled', 'failed', 'refunded', 'expired']

async function pollSwapStatus (quoteId) {
  while (true) {
    await new Promise(resolve => setTimeout(resolve, 10000))
    const { data: status } = await pods.get(`/v2/swap/status/${quoteId}`)
    console.log('Status:', status.status)
    if (TERMINAL.includes(status.status)) return status.status
  }
}
```

### 2. Pix Onramp (BRL → USDC)

Pass `destinationAddress`; the response includes `paymentInstructions.pix.copyPaste`. There is no
on-chain transaction — the user pays the Pix code.

```javascript theme={null}
const { data } = await pods.get('/v2/swap/quote', {
  params: {
    originChain: 'fiat',
    destinationChain: 'base',
    tokenIn: 'BRL',
    tokenOut: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
    amountIn: '1000', // BRL 10.00 (2 decimals)
    destinationAddress: process.env.WALLET_ADDRESS
  }
})

console.log('Pix code:', data.paymentInstructions.pix.copyPaste)
await pollSwapStatus(data.quote.quoteId)
```

### 3. Pix Offramp (USDC → BRL)

Pass `originAddress` (an approved Ramp wallet) and `pixKey`; the response includes executable
`transactionData`. Batch and sign it, then poll.

```javascript theme={null}
import { http, createWalletClient, publicActions } from 'viem'
import { base } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { executeLegsViaEip7702 } from './eip7702-batch.js'

const account = privateKeyToAccount(process.env.PRIVATE_KEY)

const { data } = await pods.get('/v2/swap/quote', {
  params: {
    originChain: 'base',
    destinationChain: 'fiat',
    tokenIn: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
    tokenOut: 'BRL',
    amountIn: '1000000', // 1.00 USDC (6 decimals)
    originAddress: account.address,
    pixKey: process.env.PIX_KEY
  }
})

const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(process.env.BASE_RPC_URL)
}).extend(publicActions)

const receipt = await executeLegsViaEip7702(walletClient, data.transactionData)
console.log('Confirmed in block:', receipt.blockNumber)
await pollSwapStatus(data.quote.quoteId)
```

### 4. Foreign USD Onramp (USD ACH/WIRE → USDC)

Pass `destinationAddress` (KYC profile must have `usdEnabled: true`). Send exactly one of `amountIn`
(USD cents) or `amountOut` (USDC base units). The response returns bank deposit instructions —
no EVM transaction to sign.

```javascript theme={null}
const { data } = await pods.get('/v2/swap/quote', {
  params: {
    originChain: 'fiat',
    destinationChain: 'polygon',
    tokenIn: 'USD',
    tokenOut: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', // USDC on Polygon
    amountOut: '4000000', // receive exactly 4 USDC
    destinationAddress: process.env.WALLET_ADDRESS,
    usdPaymentMethod: 'ACH' // or 'WIRE' (default)
  }
})

const { usd } = data.paymentInstructions
console.log('Routing:', usd.bankRoutingNumber)
console.log('Account:', usd.bankAccountNumber)
console.log('Memo (required):', usd.depositMessage)
await pollSwapStatus(data.quote.quoteId)
```

## Running the Example

<Info>
  **Download both files into the same folder** to run this example:
  [`ramp.js`](/examples/javascript/ramp.js) and the shared EIP-7702 batch helper
  [`eip7702-batch.js`](/examples/javascript/eip7702-batch.js) that it imports.
</Info>

```bash theme={null}
node ramp.js pix-onramp    # or: pix-offramp | usd-onramp
```

See the full runnable script: [`ramp.js`](/examples/javascript/ramp.js).

## Next Steps

<CardGroup cols={2}>
  <Card title="KYC (backend)" icon="id-card" href="/examples/javascript/kyc-backend">
    Onboard and approve a wallet before ramping
  </Card>

  <Card title="Move Money Guide" icon="money-bill-transfer" href="/guides/ramp/quotes">
    All Ramp routes, tokens, and fees
  </Card>

  <Card title="Track Ramp Status" icon="magnifying-glass-chart" href="/guides/ramp/status">
    Poll KYC approval and swap status
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    View complete API documentation
  </Card>
</CardGroup>
