Payments

Payments on Base: USDC, x402, and Coinbase Commerce

Accept payments on Base for $0.001 per transaction. USDC, x402 protocol for HTTP-native payments, Coinbase Commerce, and fiat onramp integration.

14 minUpdated 2026-03-03

A USDC transfer on Base costs $0.001. On Stripe, you lose 2.9% + $0.30.

For a $50 payment, that's the difference between $0.001 and $1.75 in fees. And with x402, you can paywall any API endpoint with one line of middleware. No accounts. No API keys. Just money over HTTP.

This guide covers the full stack: accepting USDC, the x402 protocol, Coinbase Commerce, fiat onramps, and building payment flows that feel like Venmo but settle onchain.

Why Base for payments

Three structural advantages beyond cost.

Native USDC: Circle mints USDC directly on Base. Not bridged, not wrapped -- real USDC with 1:1 reserves. Your compliance team can explain this to a bank.

Coinbase integration: 110M+ verified users can move funds to Base for free. That's your onramp built in.

2-second finality: payments confirm while the customer is still looking at the screen. No 10-minute Bitcoin wait. No "pending" state.

Accepting USDC payments

The simplest payment integration: accept USDC directly to a wallet or smart contract.

Direct wallet payments

For invoicing, P2P, or manual payments:

javascript
const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
const MERCHANT_WALLET = "0xYourWalletAddress";
const amount = 50_000000; // $50 in USDC (6 decimals)

const paymentLink = `ethereum:${USDC_BASE}/transfer?address=${MERCHANT_WALLET}&uint256=${amount}&chainId=8453`;

Smart contract payment receiver

For programmatic payments with automatic receipts:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract PaymentReceiver {
    IERC20 public constant USDC =
        IERC20(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913);

    event PaymentReceived(
        address indexed payer,
        uint256 amount,
        bytes32 indexed orderId
    );

    mapping(bytes32 => bool) public orderPaid;

    function pay(bytes32 orderId, uint256 amount) external {
        require(!orderPaid[orderId], "Already paid");
        require(amount > 0, "Zero amount");

        orderPaid[orderId] = true;
        USDC.transferFrom(msg.sender, address(this), amount);

        emit PaymentReceived(msg.sender, amount, orderId);
    }

    function isOrderPaid(bytes32 orderId) external view returns (bool) {
        return orderPaid[orderId];
    }
}

Listening for payments (backend)

javascript
import { createPublicClient, http, parseAbiItem } from 'viem';
import { base } from 'viem/chains';

const client = createPublicClient({
  chain: base,
  transport: http('https://mainnet.base.org'),
});

const unwatch = client.watchEvent({
  address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
  event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
  args: { to: MERCHANT_ADDRESS },
  onLogs: (logs) => {
    for (const log of logs) {
      const { from, value } = log.args;
      const amountUSD = Number(value) / 1e6;
      console.log(`Received $${amountUSD} USDC from ${from}`);
    }
  },
});

Why native USDC on Base matters

This detail matters for payments more than anything else.

USDC on Base is natively issued by Circle -- not bridged from Ethereum, not wrapped through a third-party bridge. Circle mints it directly on Base with 1:1 fiat reserves. The contract address is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913.

No bridge risk: bridged USDC on other L2s depends on the bridge contract staying solvent. Native USDC depends on Circle's reserves -- the same backing as USDC on Ethereum mainnet.

Compliance-friendly: banks and institutions recognize Circle-issued USDC. If you're building anything that touches traditional finance, native issuance eliminates a whole category of compliance questions.

Direct redemption: Circle's institutional customers can mint/redeem USDC directly on Base. Large payment volumes don't need to route through Ethereum.

Coinbase integration: moving USDC between Coinbase (the exchange) and Base is free and instant. Your customers with Coinbase accounts can fund payments with zero friction.

x402: paywall any API with one line of code

HTTP status code 402 has meant "Payment Required" since 1999. Nobody built a standard for it until now. x402 fills that gap -- and it changes how you think about monetizing anything on the internet.

The flow: client requests a resource. Server responds 402 with payment details. Client signs a USDC payment. Client retries with proof. Server serves the resource. The whole cycle takes under 3 seconds on Base.

What does that mean for you?

Charge $0.001 per API call. No signup, no API key management, no billing infrastructure. A Virtuals AI agent calls your endpoint, pays per request, and operates without a human in the loop. Direct payment from consumer to provider -- no Stripe, no 2.9% cut.

x402 SDKs and packages

x402 is an open standard (github.com/coinbase/x402) with official SDKs in TypeScript, Python, and Go. The key packages:

  • @x402/core -- core protocol logic
  • @x402/fetch -- client-side fetch wrapper
  • @x402/express -- Express.js middleware
  • @x402/next -- Next.js middleware
  • @x402/paywall -- drop-in paywall component

A facilitator service handles verification and execution -- your client and server don't deal with gas, RPC connections, or blockchain details directly.

Server implementation (Express)

The server side is literally one line of middleware:

javascript
import { paymentMiddleware } from '@x402/express';

// That's it — one line to paywall any endpoint
app.use('/api/premium', paymentMiddleware({
  price: 0.01,           // $0.01 USDC per request
  currency: 'USDC',
  network: 'base',
  recipient: MERCHANT_ADDRESS,
}));

app.get('/api/premium/data', (req, res) => {
  res.json({ data: 'Premium content here' });
});

For Next.js:

javascript
import { withPayment } from '@x402/next';

export const GET = withPayment(
  async (req) => {
    return Response.json({ data: 'Premium content' });
  },
  { price: 0.01, currency: 'USDC', network: 'base', recipient: MERCHANT_ADDRESS }
);

Client implementation

The client wraps fetch -- when it hits a 402 response, it automatically handles payment:

javascript
import { fetchWithPayment } from '@x402/fetch';

// Drop-in replacement for fetch — handles 402 automatically
const response = await fetchWithPayment('https://api.example.com/premium/data', {
  wallet: userWallet, // signs the payment
});

const data = await response.json();

The facilitator handles all the blockchain complexity. The client signs a payment, the facilitator verifies and executes it, the server gets confirmation. Neither client nor server needs to know about gas, RPC, or transaction details.

Paywall component

For content paywalls, the drop-in component:

javascript
import { Paywall } from '@x402/paywall';

function PremiumArticle() {
  return (
    <Paywall price={0.10} currency="USDC" network="base" recipient={ADDRESS}>
      <article>
        <h1>Premium Content</h1>
        <p>This content is behind an x402 paywall...</p>
      </article>
    </Paywall>
  );
}

The ecosystem is growing at x402.org/ecosystem. x402 is network/token/currency agnostic -- it works with crypto and fiat -- but USDC on Base is the natural fit given sub-cent transaction costs.

x402 use cases emerging on Base

AI agent services: agents paying for data feeds, computation, and other agent services. The Virtuals ecosystem is building toward this.

Content paywalls: pay per article, per video, per song. No subscription needed.

API monetization: weather data, price feeds, LLM inference -- any API can be monetized per-call.

IoT and machine payments: devices paying for network access, data uploads, and inter-device communication.

Coinbase has been pushing x402 as a standard, and it aligns perfectly with Base's sub-cent transaction costs. Expect this to become the default pattern for API monetization in the next year.

Stripe and the onchain payment convergence

Stripe's acquisition of Bridge (a stablecoin API company) signals serious interest in on-chain payment rails. While Stripe hasn't launched a public x402 product, their infrastructure direction points toward HTTP-native crypto payments that would let merchants accept USDC on Base through familiar Stripe APIs.

If you build x402-compatible payment endpoints now, you're positioned for potential Stripe integration when they ship their onchain payment product. The protocol is open -- any payment processor can implement it.

Coinbase Commerce

Coinbase Commerce is the simplest way to accept crypto payments with a hosted checkout experience.

How it works

  1. Create a Coinbase Commerce account at commerce.coinbase.com and generate your API key
  2. Create a charge via API when a customer initiates payment
  3. Redirect the customer to the hosted checkout page
  4. Customer pays in USDC, ETH, or BTC -- Commerce handles chain selection
  5. Receive a webhook when payment confirms on-chain (typically 2-3 seconds on Base)
  6. Funds settle to your Coinbase Commerce account
javascript
const response = await fetch('https://api.commerce.coinbase.com/charges', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CC-Api-Key': process.env.COINBASE_COMMERCE_API_KEY,
  },
  body: JSON.stringify({
    name: 'Pro Subscription',
    description: 'Monthly access to Pro features',
    pricing_type: 'fixed_price',
    local_price: { amount: '29.99', currency: 'USD' },
    metadata: { user_id: 'user_123', plan: 'pro_monthly' },
  }),
});

const charge = await response.json();
// Redirect user to charge.data.hosted_url

Webhook handling

javascript
app.post('/webhooks/coinbase', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-cc-webhook-signature'];
  const payload = req.body.toString();

  const expectedSig = crypto
    .createHmac('sha256', process.env.COINBASE_WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');

  if (signature !== expectedSig) {
    return res.status(400).send('Invalid signature');
  }

  const event = JSON.parse(payload);
  if (event.type === 'charge:confirmed') {
    activateSubscription(event.data.metadata.user_id, event.data.metadata.plan);
  }

  res.status(200).send('OK');
});

Base App: your users already have wallets

Base App replaced Coinbase Wallet. If your customer has it installed, they already have a wallet with funds on Base. No onboarding step. No "connect wallet" popup.

What does that mean for your payment UX? These users don't think of themselves as "crypto users." They have an app, a balance, and they want to pay. Hide the blockchain. No gas language, no transaction hashes in the UI, no chain IDs. Make it feel like Venmo.

Onramp and offramp solutions

Your users need to get money in and out.

Coinbase onramp

The most integrated option for Base. Users with Coinbase accounts can fund their wallet directly.

javascript
function getCoinbaseOnrampUrl({ walletAddress, amount, currency = 'USDC', chain = 'base' }) {
  const params = new URLSearchParams({
    appId: process.env.COINBASE_APP_ID,
    destinationWallets: JSON.stringify([{
      address: walletAddress,
      assets: [currency],
      supportedNetworks: [chain],
    }]),
    defaultExperience: 'buy',
    presetCryptoAmount: amount,
  });

  return `https://pay.coinbase.com/buy/select-asset?${params}`;
}

Provider comparison

Coinbase Onramp: roughly 2.5% card fees, free ACH bank transfers, 100+ countries, native Base USDC support. MoonPay: 4.5% card fees, 1-2% bank transfers, 160+ countries. Transak: 5% card fees, 1-3% bank transfers, 150+ countries.

Recommendation: offer Coinbase Onramp as primary (lowest fees for US users), MoonPay or Transak as fallback for broader coverage.

Offramps

Getting money out matters just as much. Coinbase users send USDC to Coinbase on Base, sell for fiat, withdraw to bank -- seamless. Bridge (by Stripe) enables direct USDC-to-bank-account transfers for businesses. MoonPay supports selling crypto back to fiat in many jurisdictions.

Building a complete payment flow

Here's how it all fits together for a SaaS product accepting crypto payments:

User clicks "Subscribe." Check if they have a wallet -- if not, show Coinbase Onramp or suggest Base App. Check if they have enough USDC on Base -- if not, show onramp or bridge options. Request USDC approval (if not already approved). Execute payment to PaymentReceiver contract. Backend detects PaymentReceived event. Activate subscription in database. Show confirmation to user.

Handling edge cases

User has USDC on wrong chain: offer bridging via Base Bridge or a third-party bridge aggregator. See the bridging guide for options.

User has ETH but no USDC: offer an in-app swap via Uniswap or Aerodrome. One extra transaction, but keeps the user in your flow.

Transaction fails: implement retry logic with clear error messages. Most failures are insufficient balance or approval issues.

Refunds: USDC refunds are simple -- send USDC back. Build a refund function in your contract with admin controls.

Compliance considerations

Accepting crypto payments comes with compliance responsibilities. Record every payment with wallet address, amount, timestamp, and order ID. If you're a regulated business, you may need KYC above certain thresholds (onramp providers handle KYC on their end). USDC payments are income for tax purposes. Don't accept payments from sanctioned addresses -- services like Chainalysis and TRM Labs offer screening APIs.

This isn't legal advice -- talk to a crypto-savvy lawyer for your jurisdiction.

Monitoring your payment infrastructure

Once payments are flowing, track payment success/failure rates, average confirmation time, USDC balance in your payment contracts, and unusual patterns.

Sonarbot can help monitor on-chain payment flows and alert on anomalies. Checkr provides real-time insights on token activity that complements your payment monitoring.

What's happening now

Three trends converging on Base payments:

AI agents paying for services. Virtuals' ACP (Agent Commerce Protocol) has agents transacting with each other. x402 lets any of those agents pay for API access over HTTP. This is machine-to-machine commerce, and it's live today.

Social-first commerce. Bankr users buy tokens by replying to tweets. Base App users trade inside a social feed. The payment happens inside the social context, not in a separate "wallet app."

Zero-friction consumer payments. Paymasters sponsor gas. Smart Wallets handle signing. The user taps a button and something happens. No gas popups, no approval transactions, no chain switching.

These three threads are weaving together into a payment stack that looks nothing like "crypto payments" circa 2022.

For the smart wallet integration, see Coinbase Smart Wallet guide. For dev setup, see dev environment guide.