Skip to main content

Multi-Provider Quote Comparison

This guide walks you through building a checkout experience that compares quotes across multiple payment gateways and lets users pick the best option.

Overview

The NowRamp aggregation system works in three steps:
  1. Fetch supported config — currencies, payment methods, and gateways available for your project
  2. Fetch quotes — get ranked quotes from all gateways in parallel
  3. Create checkout — send the user to the selected gateway’s checkout

Using React Hooks (@nowramp/form)

The @nowramp/form package provides hooks that handle all API calls, loading states, and cache invalidation.

Step 1: Fetch Supported Configuration

import { useRampConfig } from '@nowramp/form';

function QuoteComparison() {
  const apiConfig = {
    apiUrl: 'https://api.nowramp.com',
    projectId: 'your_project_id'
  };

  const { config, loading: configLoading } = useRampConfig(apiConfig, 'buy');

  if (configLoading) return <div>Loading...</div>;
  if (!config) return <div>Failed to load configuration</div>;

  return (
    <div>
      <h3>Available Gateways</h3>
      {config.gateways.map(gw => (
        <span key={gw.id}>
          {gw.name} {gw.features.kycHandledByProvider ? '(handles KYC)' : ''}
        </span>
      ))}

      <h3>Fiat Currencies</h3>
      <select>
        {config.fiats.map(f => (
          <option key={f.code} value={f.code}>{f.symbol} {f.name}</option>
        ))}
      </select>

      <h3>Crypto Currencies</h3>
      <select>
        {config.cryptos.map(c => (
          <option key={c.code} value={c.code}>{c.name} ({c.code})</option>
        ))}
      </select>
    </div>
  );
}

Step 2: Fetch and Display Quotes

import { useState } from 'react';
import { useRampConfig, useQuotes } from '@nowramp/form';

function QuoteComparison() {
  const apiConfig = {
    apiUrl: 'https://api.nowramp.com',
    projectId: 'your_project_id'
  };

  const { config } = useRampConfig(apiConfig, 'buy');

  const [fiatCurrency, setFiatCurrency] = useState('USD');
  const [cryptoCurrency, setCryptoCurrency] = useState('ETH');
  const [network, setNetwork] = useState('ethereum');
  const [amount, setAmount] = useState('100');

  // Quotes auto-refresh when params change
  const { quotes, loading: quotesLoading } = useQuotes(
    apiConfig,
    amount ? {
      fiatCurrency,
      fiatAmount: amount,
      cryptoCurrency,
      network,
    } : null // Pass null to skip fetching
  );

  return (
    <div>
      <input
        type="number"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
        placeholder="Amount in USD"
      />

      {quotesLoading && <div>Fetching quotes...</div>}

      {quotes?.quotes.map(quote => (
        <div key={quote.gatewayId} style={{
          border: quote.isBestRate ? '2px solid green' : '1px solid gray',
          padding: '16px',
          margin: '8px 0',
          borderRadius: '8px'
        }}>
          <h4>{quote.gatewayName} {quote.isBestRate && '(Best Rate)'}</h4>
          <p>You receive: {quote.cryptoAmount} {quote.cryptoCurrency}</p>
          <p>Rate: 1 {quote.cryptoCurrency} = {quote.exchangeRate} {quote.fiatCurrency}</p>
          <p>Fees: {quote.fees.totalFee} {quote.fiatCurrency} ({quote.fees.feePercentage}%)</p>
          <p>Time: {quote.estimatedTime}</p>
          <p>KYC: {quote.kycRequired}</p>
        </div>
      ))}

      {quotes?.unavailableGateways.map(gw => (
        <div key={gw.gatewayId} style={{ opacity: 0.5 }}>
          {gw.gatewayName}: {gw.reason}
        </div>
      ))}
    </div>
  );
}

Step 3: Create Checkout Intent

import { useCheckoutIntent, useTransaction } from '@nowramp/form';

function CheckoutFlow() {
  const apiConfig = {
    apiUrl: 'https://api.nowramp.com',
    projectId: 'your_project_id'
  };

  const { order, loading, createOrder } = useCheckoutIntent(apiConfig);

  const handleSelectQuote = async (quote) => {
    const intent = await createOrder({
      gateway: quote.gatewayId,
      fiatCurrency: quote.fiatCurrency,
      fiatAmount: quote.fiatAmount,
      cryptoCurrency: quote.cryptoCurrency,
      network: quote.network,
      walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21',
      externalCustomerId: 'user_123',
    });

    // Handle checkout based on method
    if (intent.checkout.method === 'iframe') {
      // Show iframe in your UI
      setIframeUrl(intent.checkout.url);
    } else if (intent.checkout.method === 'redirect') {
      window.location.href = intent.checkout.url;
    }
  };

  return (
    <button onClick={() => handleSelectQuote(selectedQuote)} disabled={loading}>
      {loading ? 'Creating order...' : 'Continue with selected provider'}
    </button>
  );
}

Step 4: Track Transaction

import { useTransaction } from '@nowramp/form';

function OrderTracker({ orderId }) {
  const { status, loading } = useTransaction(
    { apiUrl: 'https://api.nowramp.com' },
    orderId,
    { pollInterval: 5000, initialDelay: 15000 }
  );

  if (!status) return <div>Loading order status...</div>;

  switch (status.status) {
    case 'pending':
      return <div>Waiting for payment...</div>;
    case 'processing':
      return <div>Processing your order...</div>;
    case 'completed':
      return (
        <div>
          <h3>Purchase complete!</h3>
          <p>Received: {status.cryptoAmount} {status.cryptoCurrency}</p>
          {status.transactionHash && <p>TX: {status.transactionHash}</p>}
        </div>
      );
    case 'failed':
      return <div>Order failed. Please try again.</div>;
    default:
      return <div>Status: {status.status}</div>;
  }
}

Using Vanilla JavaScript (RampApi)

For non-React apps, use the RampApi class directly.

Complete Example

import { RampApi } from '@nowramp/sdk';

const api = new RampApi({
  projectId: 'your_project_id',
  apiUrl: 'https://api.nowramp.com'
});

// 1. Get supported configuration
const config = await api.getSupported({ orderType: 'buy' });
console.log('Gateways:', config.gateways.map(g => g.name));
console.log('Fiats:', config.fiats.map(f => f.code));
console.log('Cryptos:', config.cryptos.map(c => c.code));

// 2. Get quotes
const quotes = await api.getQuotes({
  fiatCurrency: 'USD',
  fiatAmount: '100',
  cryptoCurrency: 'ETH',
  network: 'ethereum'
});

console.log('Best rate:', quotes.bestQuote?.gatewayName,
  quotes.bestQuote?.cryptoAmount, 'ETH');
console.log('Fastest:', quotes.fastestQuote?.gatewayName);
console.log('Cheapest fees:', quotes.cheapestFees?.gatewayName);

// 3. Create checkout with the best provider
const intent = await api.createCheckoutIntent({
  gateway: quotes.bestQuote.gatewayId,
  fiatCurrency: 'USD',
  fiatAmount: '100',
  cryptoCurrency: 'ETH',
  network: 'ethereum',
  walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21',
  externalCustomerId: 'user_123'
});

// 4. Open checkout
if (intent.checkout.method === 'iframe') {
  const iframe = document.createElement('iframe');
  iframe.src = intent.checkout.url;
  iframe.width = '100%';
  iframe.height = '600';
  document.getElementById('checkout-container').appendChild(iframe);
} else {
  window.location.href = intent.checkout.url;
}

// 5. Poll for completion
const poll = setInterval(async () => {
  const tx = await api.getTransaction(intent.orderId);

  if (['completed', 'failed', 'cancelled'].includes(tx.status)) {
    clearInterval(poll);
    console.log('Final status:', tx.status);
    if (tx.transactionHash) {
      console.log('TX hash:', tx.transactionHash);
    }
  }
}, 5000);

Gateway Differences

Each gateway has different capabilities. Use the features field from getSupported() to adapt your UI dynamically. For example, some gateways support iframe-based checkout while others use a redirect or widget. Some handle KYC internally, while others may require a separate verification step.

Handling Gateway-Specific Behavior

const config = await api.getSupported();

// Filter gateways by capability
const buyGateways = config.gateways.filter(g => g.features.supportsBuy);
const sellGateways = config.gateways.filter(g => g.features.supportsSell);
const iframeGateways = config.gateways.filter(g => g.features.supportsIframe);

Quote Ranking Strategies

The API returns three pre-ranked convenience fields:
StrategyFieldDescription
Best ratebestQuoteMost crypto for your fiat
FastestfastestQuoteShortest estimated processing time
Cheapest feescheapestFeesLowest total fee amount
You can also sort by score (a 0-100 composite routing score) or implement your own ranking logic using the raw quotes array.

Error Handling

Unavailable Gateways

When a gateway can’t provide a quote, it appears in unavailableGateways:
const quotes = await api.getQuotes({ ... });

quotes.unavailableGateways.forEach(gw => {
  console.log(`${gw.gatewayName} unavailable: ${gw.reason}`);
});
Common reasons include: unsupported currency pair, amount below minimum, geographic restrictions, or provider downtime.

Amount Validation

The API validates amounts against provider limits. If an amount is out of range, you’ll get a validation error:
{
  "success": false,
  "error": "Amount 5 USD is below the minimum of 30 USD"
}
Use the minAmount and maxAmount fields from getSupported() to validate before fetching quotes.

Next Steps