OpenReceive for FastAPI

Accept Bitcoin & Stablecoin Payments With FastAPI

Include one FastAPI router and lifespan around your three host hooks. OpenReceive uses your SQLAlchemy engine for durable attempts and serves the same self-hosted checkout contract as every other adapter.

Tested live · Oct 6, 2026 · 0.4.18

Copy agent directions — Paste into Claude Code, Codex or Cursor to add OpenReceive to your FastAPI app.

Why OpenReceive

Try the checkout your customers will see

The live demo needs JavaScript: open the OpenReceive home page.

Set up

Requires Python ≥ 3.10, FastAPI ≥ 0.115.

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 FastAPI server process; see Environment variables.

4. Install

pip install "openreceive[fastapi]"

5. Wire OpenReceive — quoted from the FastAPI quickstart.

from fastapi import FastAPI
from sqlalchemy import create_engine
from openreceive.fastapi import openreceive_lifespan, openreceive_router
from openreceive.server import Host
from .app import current_user, orders  # your existing models and auth dependency

# OpenReceive's own sync Engine for its two tables — the SAME database as
# your orders, its own connection pool. On SQLite give it a dedicated Engine.
engine = create_engine("postgresql+psycopg://…")

host = Host(
    # The price for a reference — here, your order id — from your own data;
    # OpenReceive converts it into the Lightning invoice. Return None when
    # there is nothing to pay for. `value` is a decimal STRING from the order
    # row, never a float and never a request param. `description` is what the
    # payer is buying, in your own words.
    amount_for=lambda reference: (
        {"currency": "USD", "value": str(order.total), "description": order.summary}
        if (order := orders.find(reference))
        else None
    ),
    # Your own access check: may this caller do this action to this reference?
    # `context.request` is the untouched Starlette Request — reuse the same
    # dependency your order page uses. `context.resource["reference"]` is a
    # claim the payer's browser sent, not proof.
    authorize=lambda context: orders.viewer_may(
        current_user(context.request), context.resource["reference"], context.action
    ),
    # INSIDE the settlement transaction; runs only for the reference's first
    # settled attempt. Use `settlement.connection` (that transaction) for the
    # order write, never a second session. The WHERE clause is the lock.
    on_paid=lambda settlement: settlement.connection.execute(
        orders.claim_paid(settlement.reference, settlement.paid_at)
    ),
)

app = FastAPI(lifespan=openreceive_lifespan(host, engine=engine))
app.include_router(
    # Recommended for public web shops: `rate_limiting=True` caps invoice
    # creation at 60 per client IP per hour. Leave it off (the default) for
    # point-of-sale deployments, where many payers share the terminal's IP.
    openreceive_router(host, engine=engine, rate_limiting=True),
    prefix="/openreceive",
)

6. Render the checkout

import { Checkout } from "@openreceive/react";
import "@openreceive/react/styles.css";

<Checkout reference={order.id} prefix="/openreceive" />;

Full FastAPI 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, FastAPI 0.115 or later, a SQLAlchemy 2 Engine, NWC_URI in the server environment, and the generated payment-table migration applied through your normal migration tool. FastAPI quickstart

Add OpenReceive to your FastAPI app

Copy agent directions · Full quickstart · Example repository · API reference · Guides