Payment Processor
Concepts

Exchange Rates

How token prices are fetched, cached, and refreshed.

Overview

When a charge is created the API immediately fetches USD prices for every non-stablecoin token across all configured chains. These rates are stored in the database so the Worker can calculate received USD amounts without hitting CoinGecko on every block.

Rate storage

Each rate is stored as one row in PaymentTokenRate keyed by (paymentId, chain, token):

FieldDescription
usdRatePrice of 1 token in USD at the time of creation
requiredAmountHuman-readable token amount needed to cover the charge
expiresAtTimestamp after which the rate is considered stale

Refresh cycle

The Worker runs a background rateRefresher every 60 seconds. It queries for rates where expiresAt is in the past and fetches fresh prices from CoinGecko. The freshness window is controlled by payment.rateRefreshMinutes (default: 5 minutes).

t=0  charge created → rates fetched → expiresAt = t+5min
t=5  rateRefresher detects stale rate → fetches new price → expiresAt = t+10min

Stablecoins

Tokens without a coingeckoId always receive usdRate = 1. This covers USDC, USDT, DAI, etc. and avoids unnecessary API calls.

Checkout UI

The checkout page shows the customer:

  • Exact token amount required (e.g. 0.014285 ETH)
  • Current rate (e.g. 1 ETH = $3,500.00)
  • Countdown until the next rate refresh

When the rate refreshes the displayed amount updates automatically without requiring a page reload.

CoinGecko rate limits

The free CoinGecko API has a rate limit of ~30 requests/minute. For high-traffic deployments consider:

  • Using the CoinGecko Pro API (set COINGECKO_API_KEY env var)
  • Increasing payment.rateRefreshMinutes to reduce refresh frequency
  • Keeping the number of distinct coingeckoId values small

On this page