Metadata-Version: 2.5
Name: openreceive
Version: 0.4.11
Summary: Bitcoin Lightning checkout for Django, FastAPI and Python apps, with receive-only wallet access and optional USDT, USDC, ETH and SOL swaps.
Project-URL: Homepage, https://openreceive.org
Project-URL: Documentation, https://openreceive.org/guides
Project-URL: Django quickstart, https://openreceive.org/guides/quickstart-django
Project-URL: FastAPI quickstart, https://openreceive.org/guides/quickstart-fastapi
Project-URL: Wallet setup, https://openreceive.org/get_a_nwc_code_to_receive_payments
Project-URL: Swap provider setup, https://openreceive.org/set_up_swap_provider
Project-URL: Security, https://openreceive.org/guides/security
Project-URL: Issues, https://github.com/OpenReceive/openreceive/issues
Project-URL: Source, https://github.com/OpenReceive/openreceive
Project-URL: Changelog, https://github.com/OpenReceive/openreceive/blob/master/CHANGELOG.md
Author-email: OpenReceive <info@openreceive.org>
License-Expression: MIT
License-File: LICENSE
Keywords: bitcoin,django,fastapi,lightning,nostr,nwc,payments,stablecoin,usdc,usdt
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.10
Requires-Dist: coincurve>=20
Requires-Dist: cryptography>=42
Requires-Dist: httpx>=0.27
Requires-Dist: websockets<16,>=13
Provides-Extra: django
Requires-Dist: django>=5.2; extra == 'django'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.115; extra == 'fastapi'
Requires-Dist: sqlalchemy>=2; extra == 'fastapi'
Requires-Dist: starlette>=0.40; extra == 'fastapi'
Provides-Extra: flask
Requires-Dist: flask>=3; extra == 'flask'
Requires-Dist: sqlalchemy>=2; extra == 'flask'
Provides-Extra: sqlalchemy
Requires-Dist: sqlalchemy>=2; extra == 'sqlalchemy'
Description-Content-Type: text/markdown

# OpenReceive for Python

[OpenReceive](https://openreceive.org) 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](https://openreceive.org) ·
[Django quickstart](https://openreceive.org/guides/quickstart-django) ·
[FastAPI quickstart](https://openreceive.org/guides/quickstart-fastapi) ·
[All guides](https://openreceive.org/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](https://openreceive.org/guides/automated-swaps),
[provider setup](https://openreceive.org/set_up_swap_provider), and
[payer swap refunds](https://openreceive.org/guides/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](https://openreceive.org/guides/security).

## Install

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

```sh
# 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](https://openreceive.org/guides/quickstart-django)
or [FastAPI quickstart](https://openreceive.org/guides/quickstart-fastapi).
There is also a [Flask recipe](https://openreceive.org/guides/flask-recipe).
Django includes the checkout's browser assets; FastAPI and other hosts can use
OpenReceive's [frontend components](https://openreceive.org/guides/frontend-checkout).
The SQLAlchemy integration uses a synchronous engine for the payment tables.

## Connect your application

Get a [receive-only wallet connection](https://openreceive.org/get_a_nwc_code_to_receive_payments)
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](https://openreceive.org/set_up_swap_provider).

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.

- [Payment storage and migrations](https://openreceive.org/guides/storage)
- [Authorization and host responsibilities](https://openreceive.org/guides/authorization)
- [Environment variables](https://openreceive.org/guides/environment-variables)
- [Testing with fake wallets and swap providers](https://openreceive.org/guides/host-testing)
- [Deployment](https://openreceive.org/guides/deploying)

OpenReceive is open source under the MIT license.
[Source code](https://github.com/OpenReceive/openreceive) ·
[Report an issue](https://github.com/OpenReceive/openreceive/issues)

### 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](https://github.com/OpenReceive/openreceive/blob/master/docs/guides/payment-safety-upgrade.md).

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.
