Fiat Onramp (Coinbase)

NEW

Buy crypto with credit card or bank transfer via Coinbase Onramp. USDC and ETH are deposited directly to your workspace wallet on Base.

Overview
How the fiat onramp flow works
  1. Your server calls POST /api/v1/onramp/session with a PayDirect API key
  2. PayDirect generates a signed JWT, requests a one-time session token from Coinbase
  3. Returns a Coinbase Onramp URL the user can open to buy USDC or ETH
  4. Purchased crypto is deposited directly to the workspace's wallet on Base
Live only: Onramp requires a pd_live_ API key. Sandbox (pd_test_) is not supported.
POST
/api/v1/onramp/session
Create a one-time Coinbase Onramp session

Authentication

Bearer token required. pd_live_ key required — sandbox not supported.

HeaderRequiredDescription
AuthorizationYesBearer pd_live_...

Request Body

FieldTypeRequiredDescription
assetstringNo"USDC" or "ETH" — default asset in the onramp UI
fiatAmountnumberNoPreset fiat amount (1–10000)
fiatCurrencystringNoFiat currency code (default: "USD")
blockchainsstring[]NoAllowed blockchains (default: ["base"])
assetsstring[]NoAllowed assets (default: ["USDC", "ETH"])

Response (200 OK)

{
  "onramp": {
    "sessionToken": "...",
    "channelId": "...",
    "onrampUrl": "https://pay.coinbase.com/buy/select-asset?...",
    "walletAddress": "0x...",
    "expiresIn": 300
  },
  "timestamp": "2026-03-17T..."
}

Error Responses

400 — Sandbox key

{
  "error": "Coinbase Onramp is only available in live environment. Use a live API key to create onramp sessions."
}

400 — Unsupported asset

{
  "error": "Unsupported asset. Supported: USDC, ETH"
}

400 — Invalid fiat amount

{
  "error": "fiatAmount must be between 0 and 10000"
}

400 — No wallet

{
  "error": "No workspace wallet found. Provision a wallet first."
}

500 — Coinbase API failure

{
  "error": "Failed to create onramp session"
}

cURL Example

curl -X POST https://www.paydirect.com/api/v1/onramp/session \
  -H "Authorization: Bearer pd_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "asset": "USDC",
    "fiatAmount": 50,
    "fiatCurrency": "USD"
  }'

SDK Usage

const { onramp } = await client.createOnrampSession({
  asset: "USDC",
  fiatAmount: 50,
});
window.open(onramp.onrampUrl, "_blank");

Widget Usage

Use the OnrampWidget for a drop-in UI:

import { PayDirectProvider, OnrampWidget } from "@/components/widgets";

<PayDirectProvider apiKey={process.env.NEXT_PUBLIC_PAYDIRECT_API_KEY!}>
  <OnrampWidget
    defaultAsset="USDC"
    defaultFiatAmount={50}
    fiatCurrency="USD"
    mode="popup"
    onSuccess={({ onrampUrl, channelId }) => console.log("Session:", channelId)}
    onError={(err) => console.error(err)}
  />
</PayDirectProvider>

mode: "popup" opens Coinbase in a new window; "inline" embeds an iframe.

Webhook Event
Events fired when an onramp session is created
onramp.session.created

Delivered when a session is successfully created. Payload includes walletAddress, channelId, and expiresIn.

Security Notes
How we keep onramp sessions secure
  • Session tokens are single-use and expire in 5 minutes. Each call to POST /api/v1/onramp/session generates a new token.
  • CDP API keys never leave the server. PayDirect signs JWTs server-side; your frontend only receives the Coinbase Onramp URL.
  • CORS restricted to approved origins. No wildcard — only domains you configure in the dashboard can call the API from the browser.
  • JWT signed with ES256. Coinbase-compatible elliptic curve signing for token requests.