OpenReceive for Flask
Accept Bitcoin & Stablecoin Payments With Flask
Copy one file into your Flask app: a Blueprint over OpenReceive's engine, plus three hooks that set the price, decide who may pay and mark the order paid. Your SQLAlchemy engine keeps the payment attempts, and Flask-WTF's CSRF protection stays on.
Tested live · Oct 13, 2026 · 0.4.24
Copy agent directions — Paste into Claude Code, Codex or Cursor to add OpenReceive to your Flask app.
Why OpenReceive
- No OpenReceive account. There is no sign-up, no API key and no dashboard. Install the package, add a receive-only wallet code, and your server issues invoices itself.
- Open source, inside your server. MIT-licensed routes mount in the app you already run. OpenReceive never sees an order, a price or a customer, and never holds funds.
- Receive-only wallet permissions. The one credential is a receive-only NWC code. It can create invoices and read their status. It cannot spend, so a compromised server cannot drain the wallet.
- Stablecoins, optional. Connect a swap provider and customers can pay in USDT, USDC, ETH or SOL. Every payment still settles to your wallet in Bitcoin.
Try the checkout your customers will see
The live demo needs JavaScript: open the OpenReceive home page.
Set up
Requires Python ≥ 3.10, Flask ≥ 3.
1. Get a receive-only NWC code — get one here. It can issue invoices and watch for payment, and it can never spend from your wallet.
2. Get an LSC code for swaps (optional) — from a swap provider, only if customers should be able to pay in USDT, USDC, ETH or SOL.
3. Set the environment variables — NWC_URI (required) and
LSC_URI_PRIMARY / LSC_URI_BACKUP (optional) in the environment of
your Flask server process; see
Environment variables.
4. Install
pip install "openreceive[sqlalchemy]"
5. Wire OpenReceive — quoted from the Flask quickstart.
# openreceive_flask.py: OpenReceive for Flask. Copy this file into your app.
"""The OpenReceive routes as a Flask Blueprint over the framework-free engine.
`host` and `repository` are what `openreceive doctor --app app:openreceive`
reads, without touching the wallet. `start()` builds the stack once; building
the Service is the receive-only wallet check, so call it where the app boots.
"""
import os
import threading
from flask import Blueprint, Response, request
from openreceive.nwc.receive_client import NwcReceiveClient
from openreceive.server import (
ConfigurationError,
HttpRequest,
HttpResponse,
OpenReceiveApp,
Service,
)
from openreceive.server.service import redact_secrets
from openreceive.storage.sql import SqlPaymentRepository
METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
class OpenReceiveFlask:
def __init__(self, host, engine, *, rate_limiting=False):
self.host = host
# OpenReceive's own repository over your Engine: its two tables,
# the per-reference lock, write-once settlement and the reconcile gate.
self.repository = SqlPaymentRepository(engine)
self.rate_limiting = rate_limiting
self._app = None
self._lock = threading.Lock()
def start(self):
"""Build the stack once. Raises ConfigurationError when NWC_URI is
missing, unreachable or able to spend."""
with self._lock:
if self._app is None:
nwc = os.environ.get("NWC_URI", "").strip()
if not nwc:
raise ConfigurationError(
"NWC_URI is not set. Get a receive-only code: "
"https://openreceive.org/get_a_nwc_code_to_receive_payments"
)
self._app = OpenReceiveApp(
# Service reads LSC_URI_* for swaps and refuses a code that can spend.
service=Service(NwcReceiveClient(nwc)),
host=self.host,
repository=self.repository,
prefix="",
rate_limiting=self.rate_limiting,
)
return self._app
@property
def app(self):
return self.start()
def blueprint(self, url_prefix="/openreceive"):
bp = Blueprint("openreceive", __name__, url_prefix=url_prefix)
@bp.route("/<path:rest>", methods=METHODS)
def dispatch(rest):
try:
app = self.app
except ConfigurationError as error:
response = HttpResponse(
503,
{
"code": "WALLET_UNAVAILABLE",
"message": f"OpenReceive is not configured: {redact_secrets(str(error))}",
"retryable": True,
},
{},
)
else:
bodyless = request.method in ("GET", "HEAD", "OPTIONS")
response = app.handle(
HttpRequest(
method=request.method,
path=f"/{rest}",
query_string=request.query_string.decode(),
headers=dict(request.headers),
# A reader: the engine caps the body before it reads it.
body=None if bodyless else request.stream.read,
content_length=request.content_length,
remote_addr=request.remote_addr,
# What `authorize` gets as `context.request`.
framework_request=request,
)
)
return Response(
response.json(), response.status, response.headers, mimetype="application/json"
)
return bp
6. Render the checkout
from importlib.resources import files
from flask import send_from_directory
CHECKOUT_ASSETS = str(files("openreceive") / "django" / "static" / "openreceive")
@app.get("/checkout-assets/<path:name>")
def checkout_assets(name):
return send_from_directory(CHECKOUT_ASSETS, name)
Full Flask quickstart · Example app
Practical questions
- Which currencies can customers pay with?
- Bitcoin over Lightning, always. With a swap provider configured, also USDT on Tron, Solana or Ethereum, USDC on Solana or Ethereum, ETH and SOL, each converted into the same Lightning payment. Automated swaps guide
- Where does the Bitcoin go?
- Into the wallet behind your NWC code. OpenReceive never holds funds: the invoice is minted in your wallet and the sats land there. Your server confirms settlement and runs your onPaid hook once per order. Payment storage guide
- What wallet do I need?
- Any wallet that issues receive-only NWC (Nostr Wallet Connect) codes, hosted or self-run. The code must be able to create invoices and read their status, and must not be able to spend. Get a receive-only NWC code
- What does it cost?
- OpenReceive is open source and free. Fees charged by your wallet provider, by a swap provider or by Lightning routing belong to those services and are outside OpenReceive's scope.
- What do I need to deploy?
- Python 3.10 or later, Flask 3 or later, a SQLAlchemy 2 Engine, NWC_URI in the server environment, and OpenReceive's two payment tables, created by your Flask-Migrate revision or at start. Flask quickstart
Add OpenReceive to your Flask app
Copy agent directions · Full quickstart · Example repository · API reference · Guides