How to Accept Crypto Payments on Your Website
So you want to accept crypto on your website. Good news: it’s simpler than you think. Bad news: most guides overcomplicate it. Here’s the no-fluff version.
What You Actually Need
Forget running your own node or managing wallets manually. A crypto payment gateway handles the hard parts: generating payment addresses, monitoring blockchains for confirmations, and converting tokens.
You need three things:
- A wallet address to receive funds
- A payment gateway with an API
- About 20 minutes
Step 1: Choose Your Settlement Currency
This is the first decision that matters. Do you want to receive ETH? USDC? A mix?
Most merchants go with stablecoins (USDC, USDT, DAI) because the value doesn’t swing 10% overnight. With MutoPay, your customers can pay with any token, but you always receive your chosen stablecoin. Problem solved before it starts.
Step 2: Create a Channel and Get Your API Key
In your MutoPay dashboard, go to Settings → Channels and click + New channel. Give it a name (e.g. “My Website”) and optionally set a webhook URL. Your API key (ep_... prefix) is shown once — copy it.
This key identifies your channel and authenticates your API calls. Each channel has its own key, webhook URL, and can have its own settlement destination.
Step 3: Create a Payment
One API call. That’s it.
curl -X POST https://mutopay.com/api/payments \
-H "X-API-Key: ep_your_channel_api_key" \
-H "Content-Type: application/json" \
-d '{
"amount_usd": 50.00,
"description": "Order #1234 — Blue Widget",
"external_id": "order_1234",
"callback_url": "https://yoursite.com/order/1234/complete"
}'
You get back a payment object with an id. Redirect your customer to mutopay.com/pay/{id}.
Fields you can set:
| Field | Description |
|---|---|
amount_usd | Amount in USD |
amount | Amount in another currency (use with currency) |
currency | Currency code if not USD (e.g. EUR, GBP) |
description | Shown to the customer on the payment page |
external_id | Your internal reference (e.g. order ID) |
callback_url | Where to redirect the customer after payment |
metadata | Arbitrary JSON for your own use |
expires_in_minutes | 15 to 10080 (7 days); default is 60 |
Use either amount_usd or amount + currency, not both.
Step 4: Handle the Webhook
When the payment completes (or fails, or expires), MutoPay sends a POST to your channel’s webhook URL. The payload tells you everything:
{
"event": "payment.completed",
"payment_id": "pay_abc123",
"status": "completed",
"amount_usd": 50.00,
"currency": "USD",
"dest_token": "USDC",
"dest_chain_id": "137",
"dest_amount": "50000000",
"dest_decimals": 6,
"external_id": "order_1234",
"tx_hash": "0xabc...",
"completed_at": "2026-04-12T14:30:00Z",
"timestamp": "2026-04-12T14:30:01Z"
}
Verify the signature. Every webhook includes an X-MutoPay-Signature header with an HMAC-SHA256 hash of the raw JSON body, signed with your channel’s webhook secret (visible in your dashboard). Format: sha256=<hex>.
Parse the settlement amount. dest_amount is in raw token units. Divide by 10^dest_decimals to get the human-readable figure. In the example above: 50000000 / 10^6 = 50.00 USDC.
Webhook events: payment.completed, payment.failed, payment.expired, payment.underpaid, payment.kyc_required, payment.needs_manual_check.
Failed deliveries are retried 5 times with exponential backoff (1 min → 5 min → 30 min → 2 hours → 12 hours).
Step 5: Show the Customer a Payment Page
You have two options:
Redirect — send the customer to the hosted payment page at mutopay.com/pay/{id}. They select their token, connect their wallet, and pay. Zero frontend work on your end. Mobile customers see a QR code for easy deposit.
Poll — use the payment ID to build your own UI. Call GET /api/payments/{id}/status for lightweight status updates.
Most merchants start with the redirect approach and customize later.
Common Questions
What if the customer pays with a token on a different chain? The gateway handles cross-chain bridging automatically. Customer pays with ARB on Arbitrum, you receive USDC on Polygon. They don’t need to think about it.
What about refunds? Crypto payments are irreversible at the protocol level. Handle refunds by sending a separate transaction back to the customer’s wallet.
How long do payments take? Direct stablecoin transfers confirm in seconds. Cross-chain swaps typically settle in under 2 minutes.
What’s the fee? MutoPay charges 0.25% per transaction. No monthly fees, no minimums.
What chains are supported? Ethereum, Polygon, Arbitrum, Base, Optimism, Avalanche, BSC, TON, Solana, and Tron. Customers can pay with 1,000+ tokens across all 10 chains.
What’s Next
Once you’re processing payments, you’ll want to:
- Monitor payments in your merchant dashboard
- Test your webhook integration from Settings → Channels → Test Webhook
- Add a Pay Me link for tips and open-ended payments
- Explore channel management for multi-brand or multi-client setups
The whole integration takes about 20 minutes for a developer who’s done API work before. No blockchain knowledge required.