OpenReceive 0.4.22 fixes the Django install, which stopped on a system check in the quickstart's own order, and a startup crash in projects that run Django's admin. It also fixes the FastAPI quickstart wiring, Python wallet calls that timed out against TLS 1.3 relays, and Laravel 13 installs. The WordPress plugin now activates on any site and stays idle, naming what is missing, when the host lacks GMP, sodium, 64-bit PHP or MySQL. The agent directions end on a short "Setup is finished" message and check the codes with doctor instead of printenv. Upgrade if you use Django, FastAPI, Laravel 13 or the Python package.
Optional swaps let payers use USDT, USDC, SOL and ETH; a configured swap provider converts them to BTC over Lightning in the merchant's connected wallet. Asset and network availability depends on the provider.
- Fixed (Python): wallet calls (
make_invoice,list_transactions, the notification subscription) could fail with "timed out while waiting for handshake response", about one call in five againstwss://relay-nwc.rizful.com/v1in one measurement. websockets' threading client reads on a background thread while the caller writes the WebSocket upgrade request; a TLS 1.3 session ticket arriving during that write lost the request. The relay connection now uses TLS 1.2 at most, which delivers its tickets inside the handshake, with certificate checks unchanged. A new test opens 40 sessions to a local relay that sends TLS 1.3 session tickets; it failed every run before the fix. - Fixed (Laravel):
composer require openreceive/laravelrefused Laravel 13 because the package allowed onlyilluminate/*11 and 12 and the core package only brick/math below 1.0. Both now admit Laravel 13 (Symfony 8,symfony/psr-http-message-bridge8, brick/math 1.0), and the suite passes on Laravel 12 and 13. A new Laravel 13 app locks Guzzle 8, which the NWC websocket transport does not support yet, so it installs withcomposer require openreceive/laravel -W(Guzzle drops to 7, which Laravel 13 accepts); the quickstart and README say so. The Laravel directions also say that a Compose variable reaches artisan but not the web server (php artisan servehands requests only.env; php-fpm clears the environment), so the agent opens the checkout page as well as running doctor. Two trials passed doctor while every checkout returned 500. - Changed (agent directions, all eight library stacks): the closing message is at most five short lines. When the app's orders belong to a session or cookie, the agent's test order cannot open in the user's browser, so the agent now hands over the shop's own page ("Open <url> and click Buy") instead of explaining order ownership. It no longer mentions swap minimums, which filmed trials on 0.4.21 kept repeating to the user. Docs only: openreceive.org can serve this on 0.4.21.
- Changed (agent directions, all eight library stacks), from the Fastify
filmed trials on 0.4.21: when the request already names stablecoins (as
"Enable Bitcoin and stablecoin payments" does), the second message is the
lightning-swap.com walkthrough with no yes/no first, as the WooCommerce
directions already said. The agent checks the env file with
grep … | cut -d= -f1, which prints names only, instead of reading it back after a write. It restarts only the app's own server, by pid and on the app's port, never withpkillorkillallby name. Docs only. - Fixed (
openreceive doctor, npm): the bin loaded.envinto the environment before doctor read the env files, so doctor used.envbut printedenv files: none used, and.envwon over.env.local, the reverse of the documented order. Doctor now reads both files itself. - Fixed (Django):
manage.py openreceive_installstopped onopenreceive.E001("cannot be imported") when run after addingsettings.OPENRECEIVE, the quickstart's order, and the same check fires whileHOSTis unset, so the command never ran without--skip-checks.openreceive_installandopenreceive_doctorno longer run Django's system checks; doctor reports a missing host module itself. Every agent in the 0.4.21 Django filmed trials hit it. - Fixed (Django): a project that runs
django.contrib.admin, whichstartprojectinstalls, crashed at startup withTypeError: type 'ModelAdmin' is not subscriptableonceopenreceive.djangowas installed. Since 0.4.4, the ledger admin subscriptedModelAdmin, which is generic only in django-stubs. - Changed (agent directions, all eight library stacks), from the Django
filmed trials: the last message starts "Setup is finished", names what to
look at in one line and sends nothing after it (one agent of three copied
the browser checklist out after it). The agent starts the server the way
the project already does, on its own port, and when a compose file builds
the app it runs the package manager, migrations and doctor inside that
service (Laravel trial agents ran them on the host's older PHP and forced
past it with
--ignore-platform-reqs). To check that the app sees the codes, the agent runs doctor, neverprintenv: trial agents in Node, Rails and Laravel ran a names-onlyprintenvthat the directions forbid without offering another way. Django: fill inopenreceive_host.pywith the file-edit tool, never by line number. - Changed (agent directions, WooCommerce): the hand-over is at most six short lines plus the cron sentence: the pay link, the methods, one line of what to look at. It never lists each coin's availability or a minimum. All three trials on 0.4.21 ended on 10 to 14 lines calling USDT and USDC "unavailable — below the provider minimum" for a $3 order. Docs only.
- Fixed (FastAPI): the quickstart's wiring raised
ConfigurationErrorat import. It builds the app withopenreceive_lifespan(host, engine=…), then callsopenreceive_router(host, engine=…, rate_limiting=True), and the lifespan had already bound the host and engine, so the router's options were refused. The lifespan now finds its binding at startup, so either order works. The quickstart builds the router first, which also works on 0.4.21. A trial agent copying the quickstart hit it. - Fixed (docs, Express and Fastify): the quickstart's
authorizeexample passedrequestto the app's session helper.requestis a Web Request; the framework's own request isnative, and a helper that readsreq.headers.cookiefinds nothing on a Web Request, so every payer got a - A trial agent copied the pattern into a shop whose checkout then
refused its own buyers. The quickstarts, the authorization guide and the
directions now pass
native. - Changed (agent directions, all eight library stacks): the codes are written
with the file-editing tool, never a shell command, which puts the code on
the command line. The WooCommerce directions already said so; Cursor wrote
the swap code with
python3 -cin all three Fastify trials. - Agent trials, renamed from the directions eval (
npm run trial,trials/; a filmed trial is the same job on camera): a trial now fails when an OpenReceive command fails inside OpenReceive's own code (a traceback through the package, or anopenreceive.Esystem check), a flag such as--skip-checksforces past a failure, the agent rewrites the installed package (one Django agent patchedadmin.pyfrom its Dockerfile), the last doctor run is not clean, the closing message runs long, asks a question or mentions a minimum, or a command prints a code. Until now the harness never saw a failed command: Cursor files it underfailure. The eight framework shops get the live checks: the shop's own order form, a real invoice, and a second visitor with their own session refused, with the shop's log when one fails. Trials may run in parallel (--parallel); Vercel trials still go one at a time. The fixtures move to current majors: Django 6.1 with the adminstartprojectinstalls, Express 5, Rails 8.1 (withBundler.require, which the old fixture lacked) and Laravel 13. Trials no longer use a real wallet: a testkit NWC wallet service answers over a real relay and a test swap provider stands in for the real one, and after the buyer's invoice the wallet pays it and the trial checks that the shop's own order turns paid, which fails on the logging-onlyonPaidplaceholder. Each trial picks its agent at random from Cursor (Grok 4.7) and Codex by default;--agentnames one, Claude Code included. Vercel trials check the shop where it runs unless--deployis given. A Tested badge now takes three passing trials in a row, and itspassed.jsonentry names the agents and models and the directions file's hash. - Changed (WordPress): activation no longer stops with
wp_die()on a site without 64-bit PHP, GMP, sodium or MySQL. The WordPress.org review activates plugins in WordPress Playground, which runs SQLite and has neither extension, and reported the blocked activation as a failure. The plugin now activates and stays idle there: no tables, payment method, schedule or REST routes. The Plugins screen names what is missing,wp plugin activateprints it as a warning, and Doctor reports it. The tables are created on the first load once the site qualifies, and again after each plugin update, with WordPress's charset and collation. - Changed (WordPress): admin notices appear only on the Plugins screen and WooCommerce settings. The "OpenReceive is unavailable" check ran on every admin page and fetched BTC prices each time.
- Fixed (WordPress): before a wallet was configured, the every-minute reconcile action failed each run with a configuration error. It now skips the wallet scan until a wallet is configured.
- The WordPress readme's External services section says that the wallet, exchange and block-explorer links at checkout are plain links the plugin never contacts.