← Back to Blog

Crypto Payment Integration Guide: How to Add Bitcoin, Ethereum, and More to Your Web App

Crypto Payment Integration Guide · 1057 words

**Meta Description:**

Learn how to integrate crypto payments into your website or app with a step‑by‑step guide. Discover the best Python tools, developer tools, and automation tricks to accept Bitcoin, Ethereum, and other cryptocurrencies securely and efficiently.

---

1. Why Integrate Crypto Payments?

Cryptocurrencies have surged past the hype cycle and are now a mainstream payment option for merchants worldwide. By adding crypto payments to your checkout flow, you:

This guide walks you through the entire process—from choosing a payment processor to writing the Python code that handles the entire flow.

---

2. Choosing the Right Crypto Payment Processor

| Processor | Supported Coins | API Type | Fees | Key Features |

|-----------|----------------|----------|------|--------------|

| Coinbase Commerce | BTC, ETH, LTC, BCH | REST | 0.50% per transaction | Webhooks, SDKs, instant settlements |

| BitPay | BTC, BCH, ETH, XRP | REST | 1.00% per transaction | Multi‑wallet support, invoicing |

| CoinPayments | 200+ coins | REST | 0.5% per transaction | Multi‑currency, free API |

| BTCPay Server (self‑hosted) | All | REST | 0% (self‑hosted) | Full control, no escrow |

Tip: If you want zero fees and full control, consider self‑hosting BTCPay Server. For a quick start with minimal setup, Coinbase Commerce or BitPay are excellent.

---

3. Setting Up the Backend (Python)

Below is a full example using Coinbase Commerce with the official Python SDK. Replace YOUR_API_KEY with your actual API key.


pip install coinbase-commerce

# app.py
import os
from flask import Flask, request, jsonify
from coinbase_commerce.client import Client
from coinbase_commerce.error import ApiError

app = Flask(__name__)
client = Client(api_key="YOUR_API_KEY")

# Create a charge
@app.route("/create_charge", methods=["POST"])
def create_charge():
    data = request.json
    name = data.get("name", "Order")
    amount = data.get("amount", "0.01")  # in USD
    currency = "USD"

    try:
        charge = client.charge.create(
            name=name,
            description="Payment for your purchase",
            local_price={"amount": amount, "currency": currency},
            metadata={"order_id": data.get("order_id")},
            redirect_url="https://example.com/thankyou",
            cancel_url="https://example.com/cancel",
        )
        return jsonify({"charge_url": charge.hosted_url}), 201
    except ApiError as e:
        return jsonify({"error": str(e)}), 400

# Webhook to receive payment status
@app.route("/webhook", methods=["POST"])
def webhook():
    signature = request.headers.get("X-Coinbase-Webhook-Signature")
    payload = request.data.decode("utf-8")

    # Verify signature (see Coinbase docs)
    if not verify_signature(signature, payload):
        return "Signature mismatch", 400

    event = request.json
    charge = event["data"]
    status = charge["metadata"]["status"]

    if status == "COMPLETED":
        # Fulfill the order
        fulfill_order(charge["metadata"]["order_id"])
    return "OK", 200

def verify_signature(signature, payload):
    # Implement HMAC verification per Coinbase docs
    return True

def fulfill_order(order_id):
    # Your business logic to deliver goods/services
    print(f"Order {order_id} fulfilled!")

if __name__ == "__main__":
    app.run(debug=True)

3.1. Running the Server


export FLASK_APP=app.py
flask run

Your server will now expose /create_charge and /webhook endpoints. Use curl or Postman to test.

---

4. Frontend Integration

On the client side, you can simply redirect the user to the charge_url returned by the backend. If you prefer an embedded modal, Coinbase Commerce provides a JavaScript widget.


<script src="https://commerce.coinbase.com/v1/checkout.js"></script>

<button id="pay-btn">Pay with Crypto</button>

<script>
document.getElementById('pay-btn').onclick = async () => {
  const response = await fetch('/create_charge', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({name: 'Widgets', amount: '0.02', order_id: '12345'})
  });
  const data = await response.json();
  window.location.href = data.charge_url;
};
</script>

---

5. Automating Common Tasks

Automation saves time and reduces errors. Here are a few things you can automate with Python:

| Task | Automation Tool | Example |

|------|----------------|---------|

| Generate invoices | python-invoice | invoice = Invoice.create(order_id, amount) |

| Send email receipts | smtplib or SendGrid | send_email(user.email, 'Receipt', body) |

| Update inventory | SQLAlchemy | db.session.query(Product).filter_by(id=pid).update({'stock': new_stock}) |

| Slack notifications | slack_sdk | client.chat_postMessage(channel='#crypto', text='Payment received') |

**Developer Tools**: Use Docker to containerize your app, GitHub Actions for CI/CD, and Postman for API testing.

---

6. Security Checklist

| Item | Why It Matters | How to Do It |

|------|----------------|--------------|

| HTTPS | Prevent MITM attacks | Obtain a free Let’s Encrypt cert |

| Webhook verification | Ensure payloads are authentic | Verify HMAC signatures |

| Rate limiting | Thwart brute‑force attacks | Use Flask-Limiter |

| Wallet backups | Avoid losing funds | Use hardware wallets or multi‑sig solutions |

| Audit logs | Track changes | Store payment events in a secure DB |

---

7. Testing Your Integration

1. Sandbox Mode – Most processors offer a sandbox environment. Use test API keys and dummy wallets.

2. Unit Tests – Mock the API client and assert that your webhook handler correctly updates order status.

3. End‑to‑End – Use Postman to simulate a full payment flow.


# tests/test_payments.py
from unittest import mock
import pytest
from app import create_charge, webhook

def test_create_charge():
    with mock.patch('app.client.charge.create') as mock_create:
        mock_create.return_value.hosted_url = "https://commerce.coinbase.com/checkout"
        client = pytest.fixture
        resp = client.post('/create_charge', json={"name":"Test", "amount":"0.01", "order_id":"1"})
        assert resp.status_code == 201

---

8. Common Pitfalls and How to Avoid Them

| Pitfall | Symptom | Fix |

|---------|---------|-----|

| Using test keys in prod | Payment fails | Switch to live API keys |

| Ignoring webhook signatures | Fake payments processed | Verify HMAC signatures |

| Not handling refunds | Customer support issues | Implement refund API calls |

| Hard‑coding URLs | Broken when moving to prod | Store environment variables |

---

9. Scaling Up

When you start getting more traffic, consider:

---

10. Related Products

---

Final Thoughts

Adding crypto payment integration to your web app is no longer optional—it’s a differentiator. With the steps above, you can quickly set up a reliable, secure, and automated crypto payment flow using Python. Start today, and watch your global customer base grow while keeping costs low and security high. Happy coding!

🛒 Ready to deploy?

Browse 120+ Python tools with crypto payments and instant delivery.

Browse Products →