Skip to main content

OpenReceive for Python

OpenReceive adds Bitcoin and crypto checkout to your Python application. Accept BTC over Lightning directly into your wallet, and optionally let customers pay with USDT, USDC, ETH or SOL through a configured swap provider. You receive BTC over Lightning in either case.

Your application keeps its orders, prices, customers and fulfillment. OpenReceive connects checkout to your wallet, records payment attempts in your existing database, and tells your application when a payment has settled. There is no OpenReceive account to create and no separate database to operate.

Website · Django quickstart · FastAPI quickstart · All guides

How payments work

  1. Your server sets the price. OpenReceive creates a Lightning invoice in your connected wallet for the amount your application supplies.
  2. The customer chooses how to pay. They can pay the invoice directly with a Lightning wallet. With swaps enabled, they can instead send a supported asset, such as USDT or USDC, to the swap provider. The provider converts it and pays your Lightning invoice.
  3. Your wallet confirms receipt. OpenReceive records settlement and runs your application's payment hook. A swap provider saying it has finished does not count as payment: your wallet must confirm the invoice settled.

Available swap assets, networks, limits and fees depend on the configured provider. Swaps are optional; Lightning checkout works without them. See how swaps work, provider setup, and payer swap refunds.

Designed for receive-only wallet access

OpenReceive connects through Nostr Wallet Connect (NWC), using a connection code issued by your wallet. It does not need your wallet's seed phrase.

  • No spending permission required. A receive-only connection can create invoices and read payments, but cannot send funds. By default, OpenReceive refuses a connection that advertises spending methods. Bypassing that check requires an explicit override.
  • Credentials stay on your server. Neither the NWC code nor swap-provider credentials belong in browser code, logs or tests. A receive-only code is still sensitive: it can expose payment history and allow invoice creation.
  • Your application controls access and prices. Order authorization and amounts come from your server, not from the payer's browser.
  • Payments survive retries. Persistent attempts, per-order locking and write-once settlement prevent repeated payment checks from running the payment hook again for the same order.

OpenReceive does not hold your funds. Your chosen wallet determines custody; when using swaps, the provider handles the customer's deposit until payout or refund. Receive-only access limits what the integration can do, while your wallet, provider and server remain part of the trust model. Read the security guide.

Install

Requires Python 3.10 or newer. Choose the extra for your application:

# Django 5.2 or newer
pip install "openreceive[django]"

# FastAPI 0.115 or newer, with SQLAlchemy 2
pip install "openreceive[fastapi]"

# Other Python applications using SQLAlchemy 2
pip install "openreceive[sqlalchemy]"

Start with the Django quickstart or FastAPI quickstart. There is also a Flask recipe. Django includes the checkout's browser assets; FastAPI and other hosts can use OpenReceive's frontend components. The SQLAlchemy integration uses a synchronous engine for the payment tables.

Connect your application

Get a receive-only wallet connection and set NWC_URI in your server's process environment. To enable swaps, also configure LSC_URI_PRIMARY and optionally LSC_URI_BACKUP using the provider setup guide.

Your host supplies authorization, the order amount, a payment hook and its existing database connection. OpenReceive manages openreceive_payments and openreceive_meta in that database; your application applies their migrations through its normal workflow. Checkout requests drive reconciliation through a shared database gate, with an optional separate notifications worker.

OpenReceive is open source under the MIT license. Source code · Report an issue

Settlement transactions and recovery

on_paid runs inside the settlement transaction. Write the entitlement or a host outbox there; rolled-back callbacks may run again on retry. External jobs need host-owned durable idempotency. Optional after_paid is best effort after the actual commit, receives no live connection, and may be lost if the process dies between commit and delivery. Django uses transaction.on_commit on the configured database alias, including outer transactions and savepoints. MySQL explicitly rejects ambient transactions around repository reference operations because its connection-scoped lock cannot be released safely at an inner savepoint. SQLAlchemy repositories own their transaction and connection. Advanced custom repositories must implement record_settlement(..., after_commit=...) and declare supports_after_commit = True when after_paid is configured.

Explicit workers, notification fallback and request reconciliation share the same durable gate and bounded scheduler. opportunistic_reconcile=False disables only request triggers. Custom worker repositories need lease-bearing claim_reconcile_gate, checkpoint_reconcile_gate, and keyset list_reconcilable_attempts(after=..., limit=...), plus find_by_payment_hash to confirm durable settlement outcomes. Deploy application and workers together; stop old processes before upgrading. Resumed wallet history proves positive finality, never absence; a dense history can therefore leave an unpaid attempt pending until a fresh complete sweep fits its budget.

Use repository.maintenance_candidates(after=..., limit=100) for a dry-run report (candidates, next_cursor, scanned). After operator review, pass one unchanged candidate to repository.requeue_reviewed_attempt(candidate, decision_id="ticket-42"). This audits the decision and restores pending status; it does not settle or invoke fulfillment. Run the ordinary gated reconciler afterward. Reports distinguish historical early swap-deadline closure from operator-attention cases, preserve provider credentials, and never reopen settled rows. See the coordinated upgrade guide.

Storage-free RequestHandler hooks are a separate advanced API: settled polls can call on_paid repeatedly, so the host owns the conditional write/outbox. A raw on_checkout_created refusal returns 409 and withholds instructions; repository infrastructure failures return retryable 503. Public error projections omit internal details; FixedFloat diagnostic hooks expose metadata and presence flags, never raw request bodies or provider responses.

Agent skills

Run openreceive skills install from your application to install the offline skills bundled in the openreceive package. See agent setup. The bundled installers write to .agents/skills/; use --dir .claude/skills for Claude Code. They replace only integrate-openreceive and debug-openreceive-payment, preserving unrelated skills.

Metadata

Release files for openreceive 0.4.19

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openreceive 0.4.19
File Size Uploaded Provenance
openreceive-0.4.19.tar.gz 1.1 MB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for openreceive 0.4.19
File Interpreter ABI Platform
openreceive-0.4.19-py3-none-any.whl Python 3 none any Details

Total release size: 2.2 MB

Release files / openreceive-0.4.19.tar.gz

Download URL openreceive-0.4.19.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
3dc03fb7355276928d90a3896db8cac9d1d032e9cb47447e5faca656c1cfd70a
BLAKE2b-256 checksum
How to use checksums
42628e25ad146912e8c294a2242eb619209322f02a5cf527a829f98c3ccdccf4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / openreceive-0.4.19-py3-none-any.whl

Download URL openreceive-0.4.19-py3-none-any.whl
Size 1.1 MB
Tags Python 3
SHA-256 checksum
How to use checksums
74b5c6eac6138eb727e7a0f5d880ee2dee59c17b057d2afd567644607cedcf86
BLAKE2b-256 checksum
How to use checksums
ad87864df2136e09722f81b26a71baafa74b681f64cf94f3feae81288295972b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for openreceive 0.4.19

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page