Skip to content
Back to Monetization & Revenue

Crypto Payment

How to accept USDC/USDT/BTC via a payment gateway like Coinbase Commerce or NOWPayments without holding crypto on your books.

Why

A small but vocal segment of users — privacy-conscious developers, crypto-native products, and customers in countries blocked by Stripe — will only pay in crypto. Accepting stablecoins (USDC/USDT) gives you this revenue without the volatility risk of holding BTC, because the gateway auto-converts to fiat at settlement. The compliance burden is lower than it appears: if you use a hosted gateway and never touch a private key, you are not a money transmitter in most jurisdictions. The main cost is accounting complexity — crypto payments are taxable events at the time of receipt, so you need a tool like Koinly to track cost basis. For most SaaS this is a 2-5% revenue unlock for a 1-day integration.

When

When you have crypto-native users, sell to sanctioned-adjacent regions, or run a privacy product. Skip if your audience is enterprise procurement — they cannot pay in crypto.

How

1. Choose a gateway: Coinbase Commerce (hosted checkout, US only), NOWPayments (global, 50+ coins), or BitPay (enterprise). Avoid self-hosting unless you have a compliance team.
2. Create an account, complete KYB (know-your-business), and generate an API key
3. For each checkout, create a charge server-side: POST /v1/charges with the fiat amount, the gateway converts to the selected coin at the locked rate
4. Redirect the user to the hosted checkout page, or embed the gateway's widget in your page
5. Set up a webhook for charge:confirmed and charge:failed — the gateway waits for on-chain confirmation (typically 1-3 blocks) before confirming
6. On confirmation, grant the entitlement; store the txid and coin for refund/reconciliation
7. Configure auto-settlement to fiat so you never hold crypto overnight ( Coinbase Commerce does this by default)
8. For refunds, issue a refund through the gateway API with the original charge id — never send crypto back manually

Example

// server: create a Coinbase Commerce charge
const res = await fetch("https://api.commerce.coinbase.com/charges", {
  method: "POST",
  headers: {
    "X-CC-Api-Key": process.env.COINBASE_COMMERCE_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Pro plan — monthly",
    description: "EZ4Code Pro subscription",
    pricing_type: "fixed_price",
    local_price: { amount: "29.00", currency: "USD" },
    metadata: { userId: user.id },
  }),
});
const { data } = await res.json();
// redirect to data.hosted_url

// webhook: wait for on-chain confirmation
app.post("/api/crypto-webhook", async (req, res) => {
  const event = req.body;
  if (event.type === "charge:confirmed") {
    const userId = event.data.metadata.userId;
    await grantEntitlement(userId, { source: "crypto", txid: event.data.id });
  }
  res.status(200).send("ok");
});

Common Problems

  • ⚠Accepting volatile coins (BTC/ETH) without auto-conversion — the price drops 20% between charge and confirmation and you sold a $99 plan for $79. Use stablecoins or enable auto-convert to fiat.
  • ⚠Not waiting for on-chain confirmation before granting access — a user can broadcast a double-spend and get entitlement revoked. Always wait for the gateway's charge:confirmed event, which implies N confirmations.
  • ⚠Manually sending crypto back for refunds — if you mistype the address the refund is gone forever with no recourse. Always refund through the gateway API which tracks the original charge.

Best Practices

  • ✓Default to stablecoins (USDC/USDT) and offer BTC as a secondary option — stablecoins give you the crypto audience without the treasury management headache.
  • ✓Use a hosted checkout page rather than embedding payment widgets — the gateway handles wallet connection, QR codes, and chain selection, and you avoid touching any wallet logic.
  • ✓Record the fiat amount at the time of charge, not the crypto amount — for accounting you report the USD value when received, and the gateway's settlement report gives you the cost basis.