openreceive 0.4.21 → 0.4.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfeec42ce821ad2ab73b5140eb1959f76f4125c34f26bfd214cc0e68ef507a00
4
- data.tar.gz: '09f6e1227799a8d50cab35b0b2e69d4eb6509e55f4e6cbbff9e5067c50fb9b06'
3
+ metadata.gz: fb5542a9163a02e90baa6f8938172785600029980002c119fde4631b452da20c
4
+ data.tar.gz: 7f71eb77da79968df633485d01ca9e7a89bbd839186a1daf1d137323f889daba
5
5
  SHA512:
6
- metadata.gz: 0bc687a6d13e167aa2ad2a9dbfc1286058177be57a245424e8ad8e0e911631579296b1520c3fa4876baca6562570b3fdeaadc3fd49576c49752102a72f939bc6
7
- data.tar.gz: 64ab63dda22aafcac83e0b831ebc3ab17b441145eb07250516e2de2c8141eb7ebeb4cd812ac274fe1427df1c94e96fe00ec45b2b94c1aac47c89a07aa57b5d6b
6
+ metadata.gz: 75465da88449b28ff097b5b4a4d7eadb141e2ba8be2a1e4797ae021fd23ba876df3b50cbef86e7afb0b05df4f718e957dd78a5c4979cda2558e79bb9642c20c4
7
+ data.tar.gz: 90884d4fef6027acb5919a5a9d36c0e7d1ba066d13d21db1793c940dad7c2c6653288a26efb0540eccb7b7baf37a4817e99d3826fb58af034aa594bc303ff260
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.23 - 2026-10-11
4
+
5
+ Release with the complete 0.4.23 package family. The bundled agent skill adds
6
+ directions for Lovable's agent. Its BTCPay Server directions ask for one code
7
+ per message and never search the machine for one, its WooCommerce directions
8
+ install the plugin from WordPress.org, and its Laravel directions add GMP to
9
+ the Docker image. No Ruby runtime changes from 0.4.22.
10
+
11
+ ## 0.4.22 - 2026-10-10
12
+
13
+ Release with the complete 0.4.22 package family. The bundled agent skills'
14
+ directions now end with a message that starts "Setup is finished" and sends
15
+ nothing after it. They write the codes with the file-editing tool, check the
16
+ app sees them with doctor rather than `printenv`, start the server the way
17
+ the project already does, and restart only the app's own server by pid. No
18
+ Ruby runtime changes from 0.4.21.
19
+
3
20
  ## 0.4.21 - 2026-10-09
4
21
 
5
22
  Release with the complete 0.4.21 package family. The bundled agent skills'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenReceive
4
- VERSION = "0.4.21"
4
+ VERSION = "0.4.23"
5
5
  end
@@ -38,6 +38,9 @@ connected wallet; asset and network availability depends on the provider.
38
38
  - Django: [references/django.md](references/django.md)
39
39
  - Laravel: [references/laravel.md](references/laravel.md)
40
40
  - WordPress + WooCommerce: [references/woocommerce.md](references/woocommerce.md) — the packaged gateway and merchant settings.
41
+ - Lovable (TanStack Start on Cloudflare Workers, with Supabase):
42
+ [references/lovable.md](references/lovable.md) — no terminal; codes are
43
+ Lovable secrets and payments go through Supabase's HTTPS API.
41
44
  - BTCPay Server: [references/btcpay.md](references/btcpay.md) — a plugin,
42
45
  configured in BTCPay's store UI or Greenfield API; no application code,
43
46
  no npm packages, no gem. The rest of this file is about the library.
@@ -3,7 +3,7 @@ This is the full file; follow it from Step 0.
3
3
  # OpenReceive agent directions (BTCPay Server)
4
4
 
5
5
  ```sh
6
- # READ THIS FIRST: this file is 12 KB and a summary drops required steps. Download it whole:
6
+ # READ THIS FIRST: this file is 16 KB and a summary drops required steps. Download it whole:
7
7
  curl -fsSL https://openreceive.org/agent-directions/btcpay/full.md
8
8
  # Skip the download only if you already have all of it: pasted, read from disk or fetched raw.
9
9
  ```
@@ -17,7 +17,7 @@ curl -fsSL https://openreceive.org/agent-directions/btcpay/full.md
17
17
  - Never tick the spend-capable override to make a save succeed.
18
18
  - Do not suggest rotating or revoking a code because it was pasted here.
19
19
 
20
- These directions describe OpenReceive 0.4.21.
20
+ These directions describe OpenReceive 0.4.23.
21
21
 
22
22
  Connect a BTCPay Server store to a receive-only NWC wallet with the OpenReceive
23
23
  plugin, and optionally let payers pay BTCPay invoices with USDT, USDC, ETH or
@@ -54,31 +54,84 @@ refund path on the same checkout screen.
54
54
  BTCPay refuses to load it below.
55
55
  2. Check whether the plugin is installed (the Plugins menu — the plug icon in
56
56
  the top-right corner — under Installed Plugins, or the store navigation
57
- shows an "OpenReceive" entry). If not, install it from the BTCPay plugin
58
- directory (the same Plugins menu → Plugin Directory, search "openreceive",
59
- then Install and Restart now), as the quickstart says; do not invent an
60
- installer command.
57
+ shows an "OpenReceive" entry; through Greenfield,
58
+ `GET /api/v1/stores/{storeId}/openreceive/settings` answers 404 until it
59
+ is). If not, install it from the BTCPay plugin directory (the same Plugins
60
+ menu → Plugin Directory, search "openreceive", then Install and Restart
61
+ now), as the quickstart says; do not invent an installer command. BTCPay
62
+ installs plugins only from its UI. If you cannot use it, ask the user to:
63
+ name those clicks, and wait until they say it is installed.
61
64
  3. Check whether the store already has an OpenReceive connection:
62
65
  `GET /api/v1/stores/{storeId}/openreceive/settings` returns
63
- `lightningNodeIsOpenReceive`. If true, the wallet step is done — go to
64
- swaps only if the user wants them.
65
- 4. If no receive-only NWC code is available, stop and tell the user exactly
66
- what to create:
67
-
68
- > OpenReceive cannot mint an invoice without a receive-only NWC code. Get
69
- > one at https://openreceive.org/get_a_nwc_code_to_receive_payments and
70
- > paste it into Store → OpenReceive → Test connection, or hand it to me and
71
- > I will set it through the Greenfield API.
72
-
73
- Never print, log or echo the code; report only whether it is set. Never
74
- paste a bare `nostr+walletconnect://` string into BTCPay's Lightning node
75
- screen — that form is claimed by the Nostr plugin, without the receive-only
76
- guard.
77
- 5. If the user wants altcoin payments, ask for an LSC code from
78
- https://openreceive.org/set_up_swap_provider. Do not wait for it: the
79
- wallet works without it, and swaps switch on later with one settings change.
80
-
81
- Only then start the quickstart.
66
+ `lightningNodeIsOpenReceive` and `lscPrimaryConfigured`. A code that is
67
+ already saved is not asked for again; if both are, skip to Verifying.
68
+
69
+ Otherwise your next action is a question to the user. A store without a
70
+ connection has no code anywhere on this machine. Do not search for one: do not
71
+ read other files, Docker containers, compose files beyond this deployment's,
72
+ or process environments, and never run `printenv`. Hunting for a code burns
73
+ the turn and can leak other secrets into the transcript.
74
+
75
+ The user never edits BTCPay's settings for you. They paste each code
76
+ into the chat; you save it (Step 1). Ask one question per message:
77
+
78
+ 1. **First message — the NWC code, and nothing else.** Ask for it and walk them
79
+ through getting it:
80
+
81
+ > To receive payments I need a receive-only wallet code. In Rizful: open
82
+ > the menu, tap NWC, choose Receive-only NWC code, and tap Copy
83
+ > (https://openreceive.org/get_a_nwc_code_to_receive_payments). If you would
84
+ > rather run your own wallet, Alby Hub works too: Connections → Add
85
+ > Connection → Read Only. Paste the code here and I will save it in
86
+ > BTCPay.
87
+
88
+ If the plugin still needs installing, ask for that in the same message.
89
+ 2. **When they paste it.** If it does not start with `nostr+walletconnect://`,
90
+ ask them to copy the receive-only code again. Otherwise save it (Step 1),
91
+ reply only that it is saved, then ask the next question. Never print, log
92
+ or echo the code; report only whether it is set. Never paste a bare
93
+ `nostr+walletconnect://` string into BTCPay's Lightning node screen — that
94
+ form is claimed by the Nostr plugin, without the receive-only guard.
95
+ 3. **Second message — swaps.** If the user asked for stablecoins, USDT, USDC,
96
+ ETH, SOL, altcoins or "crypto" (as in "Bitcoin and stablecoin payments"),
97
+ this message IS the walkthrough below: send it as it is, and do not ask yes
98
+ or no first. Otherwise ask whether payers should also be able to pay with
99
+ USDT, USDC, ETH or SOL, then give the walkthrough. The walkthrough:
100
+
101
+ > Go to https://lightning-swap.com, sign in for API keys, create a key, and
102
+ > copy the whole URI (https://openreceive.org/set_up_swap_provider). Paste
103
+ > it here and I will save it — or say "Bitcoin only" and I will continue
104
+ > without it.
105
+
106
+ Mention FixedFloat only if they already use it.
107
+ 4. **When they paste it.** If it does not start with
108
+ `lightning+swapconnect://`, ask them to copy it again. Otherwise save it
109
+ (Step 1); saving it turns swaps on.
110
+
111
+ The quickstart below shows the same steps in BTCPay's UI.
112
+
113
+ ## Step 1 — save the codes through the Greenfield API
114
+
115
+ Use a Greenfield API key the user gives you (Account → API Keys) that can
116
+ modify the store's settings. A swap provider on a local network needs a server
117
+ admin's key. Save each code yourself, one request each, and never in a
118
+ command line:
119
+
120
+ 1. Write the request body with your file-editing tool, not a shell command (no
121
+ `echo`, `printf` or heredoc), to a new file outside the deployment
122
+ directory, such as `/tmp/openreceive-settings.json`:
123
+ `{"nwcUri": "<the NWC code>"}`. For the LSC code the body is
124
+ `{"lscPrimary": "<the LSC code>"}`; saving it turns swaps on.
125
+ 2. Send it, with your server's address, the key and the store id:
126
+ `curl -fsS -X PUT -H "Authorization: token $BTCPAY_API_KEY" -H "Content-Type: application/json" --data @/tmp/openreceive-settings.json "$BTCPAY_URL/api/v1/stores/$BTCPAY_STORE_ID/openreceive/settings"`.
127
+ 3. Delete the file (`rm /tmp/openreceive-settings.json`), whether the request
128
+ passed or not.
129
+
130
+ The response never contains a code. `lightningNodeIsOpenReceive: true` means
131
+ the wallet is saved; `swapsEnabled` and `lscPrimaryConfigured` say the same
132
+ for swaps. A refusal answers 422 with a `code` and a `message`: a code that
133
+ can spend is refused on purpose, so ask the user for a receive-only code
134
+ instead of setting the override.
82
135
 
83
136
  ## Non-negotiables
84
137
 
@@ -121,11 +174,16 @@ Only then start the quickstart.
121
174
 
122
175
  Store → OpenReceive → **Run a health check** (the doctor page) runs every probe now: connection, preflight,
123
176
  notifications, last scan, provider reachability, invoice expiration, swaps
124
- needing attention. On a regtest machine, `packages/dotnet/docker/up.sh` then
177
+ needing attention. Without the UI, check through Greenfield instead:
178
+ `GET /api/v1/stores/{storeId}/openreceive/settings` shows the wallet and
179
+ swaps, `POST /api/v1/stores/{storeId}/openreceive/wallet/test` with `{}`
180
+ runs the wallet preflight again, and a test invoice
181
+ (`POST /api/v1/stores/{storeId}/invoices` with an amount) must list a
182
+ `BTC-LN` payment method whose `destination` is a BOLT11. On a regtest machine, `packages/dotnet/docker/up.sh` then
125
183
  `e2e.sh` in the OpenReceive repository proves the whole path end to end, and
126
184
  that is the only situation where cloning the repository is the right move.
127
185
 
128
- Setup ends when the health check is clean. Say "Setup is finished" in one
186
+ Setup ends when the health check, or those Greenfield checks, are clean. Say "Setup is finished" in one
129
187
  message. Do not offer more work or end the message on a question.
130
188
 
131
189
  ## More documentation
@@ -3,7 +3,7 @@ This is the full file; follow it from Step 0.
3
3
  # OpenReceive agent directions (Django)
4
4
 
5
5
  ```sh
6
- # READ THIS FIRST: this file is 44 KB and a summary drops required steps. Download it whole:
6
+ # READ THIS FIRST: this file is 46 KB and a summary drops required steps. Download it whole:
7
7
  curl -fsSL https://openreceive.org/agent-directions/django/full.md
8
8
  # Skip the download only if you already have all of it: pasted, read from disk or fetched raw.
9
9
  ```
@@ -17,7 +17,7 @@ curl -fsSL https://openreceive.org/agent-directions/django/full.md
17
17
  - Do not suggest rotating or revoking a code because it was pasted here.
18
18
  - Start the quickstart only once the NWC code is saved, and the LSC code is saved or the user said "Bitcoin only".
19
19
 
20
- These directions describe OpenReceive 0.4.21.
20
+ These directions describe OpenReceive 0.4.23.
21
21
 
22
22
  Add OpenReceive to a Django project — the app you are already working in. You
23
23
  do not need a copy of the OpenReceive source: the Python package is on PyPI
@@ -61,11 +61,12 @@ owns orders, users, prices, or fulfillment.
61
61
 
62
62
  ## Step 0 — ask for the two codes, one question at a time
63
63
 
64
- Before anything else, look at one file: the project's `.env`, if it exists.
65
- Read it only far enough to see whether `NWC_URI` and `LSC_URI_PRIMARY` are
66
- there and non-empty, and never print the values. A code that is already
67
- set is not asked for again; if both are set, skip to step 5
68
- (making the server load the file), then the quickstart.
64
+ Before anything else, check one file: the project's `.env`, if it exists.
65
+ `grep -E '^(NWC_URI|LSC_URI_PRIMARY)=.' .env | cut -d= -f1` names the codes
66
+ it sets without printing them. Check with that, here and after each write,
67
+ not by reading the file, and never print the values. A code that is already
68
+ set is not asked for again; if both are set, skip to step 5 (making the
69
+ server load the file), then the quickstart.
69
70
 
70
71
  Otherwise your next action is a question to the user. Do not install the package,
71
72
  edit the app, write `.env.example`, or search anywhere else before asking
@@ -96,14 +97,17 @@ you store it. Ask one question per message.
96
97
  Do not mention `.env`, exports, or "tell me when it's set".
97
98
  2. **When they paste it.** If it does not start with `nostr+walletconnect://`,
98
99
  ask them to copy the receive-only code again. Otherwise write
99
- `NWC_URI=<paste>` into the project's `.env`, creating the file if needed.
100
- Make sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has
101
- one). Never echo the value, commit it, or put it in client code. Reply only
102
- that it is saved, then ask the next question.
103
- 3. **Second message — swaps.** If the user already asked for stablecoins or
104
- altcoins, skip the yes/no and go straight to the walkthrough. Otherwise ask
105
- whether payers should also be able to pay with USDT, USDC, ETH or SOL. The
106
- walkthrough:
100
+ `NWC_URI=<paste>` into the project's `.env` with your file-editing tool,
101
+ creating the file if needed. Never write it with a shell command (`echo`,
102
+ `printf`, a heredoc, `python -c`): the command line shows the code. Make
103
+ sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has one).
104
+ Never echo the value, commit it, or put it in client code. Reply only that
105
+ it is saved, then ask the next question.
106
+ 3. **Second message — swaps.** If the user asked for stablecoins, USDT, USDC,
107
+ ETH, SOL, altcoins or "crypto" (as in "Bitcoin and stablecoin payments"),
108
+ this message IS the walkthrough below: send it as it is, and do not ask yes
109
+ or no first. Otherwise ask whether payers should also be able to pay with
110
+ USDT, USDC, ETH or SOL, then give the walkthrough. The walkthrough:
107
111
 
108
112
  > Go to https://lightning-swap.com, sign in for API keys, create a key, and
109
113
  > copy the whole URI (https://openreceive.org/set_up_swap_provider). Paste
@@ -113,10 +117,10 @@ you store it. Ask one question per message.
113
117
  Mention FixedFloat only if they already use it.
114
118
  4. **When they paste it.** If it does not start with
115
119
  `lightning+swapconnect://`, ask them to copy it again. Otherwise add
116
- `LSC_URI_PRIMARY=<paste>` to the same `.env`, without echoing it. Swaps
117
- are now on, so build the refund route back (the swap non-negotiable below) as
118
- part of this integration. If they chose Bitcoin only, leave
119
- `LSC_URI_PRIMARY` unset and skip that route.
120
+ `LSC_URI_PRIMARY=<paste>` to the same `.env` with the file-editing tool,
121
+ never a shell command. Swaps are now on, so build the refund route back
122
+ (the swap non-negotiable below) as part of this integration. If they chose
123
+ Bitcoin only, leave `LSC_URI_PRIMARY` unset and skip that route.
120
124
  5. **Make the server load the file — yourself.** Django does not
121
125
  read `.env` on its own. If the app already uses `django-environ`, make sure
122
126
  it reads this file; otherwise add it and call `environ.Env.read_env()` in
@@ -160,22 +164,28 @@ failed check and exits nonzero; fix it before going on.
160
164
 
161
165
  Give the user that checkout link. The browser check in the quickstart's
162
166
  "Render the checkout" section (payment-method icons, wallet logos, a pay
163
- tutorial) is theirs: tell them what to look at, and do not run it yourself.
167
+ tutorial) is theirs: name it in one line of your closing message, and do not
168
+ run it yourself.
164
169
 
165
170
  You cannot pay the invoice: the code is receive-only. Do not pay, settle or
166
171
  mark an order paid, and do not look for a way to (a wallet control port, a
167
172
  test endpoint, another wallet). If the user wants a real settlement test, they
168
173
  pay on that link from their own wallet, and `on_paid` marks the order paid.
169
174
 
170
- Setup ends here. Say "Setup is finished" in one message of at most five
171
- lines, with the link and what to check. Do not list what changed, offer more
172
- work, or end the message on a question.
175
+ Setup ends here. Your last message starts "Setup is finished" and has at most
176
+ five short lines (about 80 characters each): the link, the methods it offers,
177
+ and one line of what to look at. Send nothing after it. Do not list what
178
+ changed, copy out the quickstart's browser checklist, offer more work, or end
179
+ the message on a question.
173
180
 
174
181
  - The link is to a real unpaid order. Keep that order; do not delete it.
182
+ - When this app's orders belong to a session or cookie, the user's browser
183
+ cannot open the order you made. Then the link is the shop's own page:
184
+ "Open <shop url> and click Buy: it opens the checkout." Do not explain order
185
+ ownership or mention your test order.
175
186
  - Name the methods it offers: Bitcoin, plus USDT, USDC, ETH and SOL when
176
- `LSC_URI_PRIMARY` is saved. Never say a coin will not work or will not be
177
- offered. Swap minimums apply per order, and a coin whose minimum is above an
178
- order's total says so on its own tile.
187
+ `LSC_URI_PRIMARY` is saved. Do not mention minimums, and never say a coin
188
+ will not work or will not be offered.
179
189
 
180
190
  ## Non-negotiables
181
191
 
@@ -192,6 +202,21 @@ itself, and they hold for every integration.
192
202
  - Work only in this application. Never read or run anything from another
193
203
  project on this machine (its `node_modules`, tools or source), for any
194
204
  reason. A browser and Playwright are not part of setup.
205
+ - Restart only this app's server, on the port it already uses: stop the
206
+ process you started, or the one listening on that port, by its pid (or
207
+ restart its Compose service). Never `pkill` or `killall` by name: that
208
+ stops other people's servers too. Start it the way this project already
209
+ does (its README, Procfile, compose file or package script), on its own
210
+ port, not a port you pick.
211
+ - Run commands where the app runs. When a compose file builds it, run its
212
+ package manager, generators, migrations and doctor inside that service
213
+ (`docker compose exec` or `run`), and rebuild the image after adding a
214
+ package. This machine's language version and database path are not the
215
+ app's.
216
+ - To check that the running app sees the codes, run doctor: it reports each
217
+ one as present or missing and never prints a value. Never print the
218
+ environment (`printenv`, `env`, `docker compose config`), even filtered to
219
+ names.
195
220
  - The host owns the price. `amount_for` reads it from your own data;
196
221
  reject payer-supplied amounts.
197
222
  - `authorize` runs on every request, and the `resource` it receives is a
@@ -200,6 +225,10 @@ itself, and they hold for every integration.
200
225
  a placeholder that allows everything (`manage.py check` warns
201
226
  `openreceive.W002` while it is set) — replace it with this app's real
202
227
  ownership check, same as `on_paid`.
228
+ - Fill in `openreceive_host.py` with your file-edit tool: replace each
229
+ placeholder in place (the `authorize = staticmethod(...)` line, the
230
+ `amount_for` body, the `on_paid = staticmethod(...)` line). Never edit it
231
+ by line number from a script.
203
232
  - `on_paid` must be idempotent. Its database fulfillment commits once per `reference` — your order
204
233
  id, one per thing you fulfill, created before checkout, kept across retries,
205
234
  never reused. A fresh id per page load lets one order be paid twice.
@@ -3,7 +3,7 @@ This is the full file; follow it from Step 0.
3
3
  # OpenReceive agent directions (FastAPI)
4
4
 
5
5
  ```sh
6
- # READ THIS FIRST: this file is 37 KB and a summary drops required steps. Download it whole:
6
+ # READ THIS FIRST: this file is 39 KB and a summary drops required steps. Download it whole:
7
7
  curl -fsSL https://openreceive.org/agent-directions/fastapi/full.md
8
8
  # Skip the download only if you already have all of it: pasted, read from disk or fetched raw.
9
9
  ```
@@ -17,7 +17,7 @@ curl -fsSL https://openreceive.org/agent-directions/fastapi/full.md
17
17
  - Do not suggest rotating or revoking a code because it was pasted here.
18
18
  - Start the quickstart only once the NWC code is saved, and the LSC code is saved or the user said "Bitcoin only".
19
19
 
20
- These directions describe OpenReceive 0.4.21.
20
+ These directions describe OpenReceive 0.4.23.
21
21
 
22
22
  Add OpenReceive to a FastAPI application — the app you are already working in.
23
23
  You do not need a copy of the OpenReceive source: the engine is on PyPI
@@ -61,11 +61,12 @@ owns orders, users, prices, or fulfillment.
61
61
 
62
62
  ## Step 0 — ask for the two codes, one question at a time
63
63
 
64
- Before anything else, look at one file: the project's `.env`, if it exists.
65
- Read it only far enough to see whether `NWC_URI` and `LSC_URI_PRIMARY` are
66
- there and non-empty, and never print the values. A code that is already
67
- set is not asked for again; if both are set, skip to step 5
68
- (making the server load the file), then the quickstart.
64
+ Before anything else, check one file: the project's `.env`, if it exists.
65
+ `grep -E '^(NWC_URI|LSC_URI_PRIMARY)=.' .env | cut -d= -f1` names the codes
66
+ it sets without printing them. Check with that, here and after each write,
67
+ not by reading the file, and never print the values. A code that is already
68
+ set is not asked for again; if both are set, skip to step 5 (making the
69
+ server load the file), then the quickstart.
69
70
 
70
71
  Otherwise your next action is a question to the user. Do not install packages,
71
72
  edit the app, write `.env.example`, or search anywhere else before asking
@@ -96,14 +97,17 @@ you store it. Ask one question per message.
96
97
  Do not mention `.env`, exports, or "tell me when it's set".
97
98
  2. **When they paste it.** If it does not start with `nostr+walletconnect://`,
98
99
  ask them to copy the receive-only code again. Otherwise write
99
- `NWC_URI=<paste>` into the project's `.env`, creating the file if needed.
100
- Make sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has
101
- one). Never echo the value, commit it, or put it in client code. Reply only
102
- that it is saved, then ask the next question.
103
- 3. **Second message — swaps.** If the user already asked for stablecoins or
104
- altcoins, skip the yes/no and go straight to the walkthrough. Otherwise ask
105
- whether payers should also be able to pay with USDT, USDC, ETH or SOL. The
106
- walkthrough:
100
+ `NWC_URI=<paste>` into the project's `.env` with your file-editing tool,
101
+ creating the file if needed. Never write it with a shell command (`echo`,
102
+ `printf`, a heredoc, `python -c`): the command line shows the code. Make
103
+ sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has one).
104
+ Never echo the value, commit it, or put it in client code. Reply only that
105
+ it is saved, then ask the next question.
106
+ 3. **Second message — swaps.** If the user asked for stablecoins, USDT, USDC,
107
+ ETH, SOL, altcoins or "crypto" (as in "Bitcoin and stablecoin payments"),
108
+ this message IS the walkthrough below: send it as it is, and do not ask yes
109
+ or no first. Otherwise ask whether payers should also be able to pay with
110
+ USDT, USDC, ETH or SOL, then give the walkthrough. The walkthrough:
107
111
 
108
112
  > Go to https://lightning-swap.com, sign in for API keys, create a key, and
109
113
  > copy the whole URI (https://openreceive.org/set_up_swap_provider). Paste
@@ -113,10 +117,10 @@ you store it. Ask one question per message.
113
117
  Mention FixedFloat only if they already use it.
114
118
  4. **When they paste it.** If it does not start with
115
119
  `lightning+swapconnect://`, ask them to copy it again. Otherwise add
116
- `LSC_URI_PRIMARY=<paste>` to the same `.env`, without echoing it. Swaps
117
- are now on, so build the refund route back (the swap non-negotiable below) as
118
- part of this integration. If they chose Bitcoin only, leave
119
- `LSC_URI_PRIMARY` unset and skip that route.
120
+ `LSC_URI_PRIMARY=<paste>` to the same `.env` with the file-editing tool,
121
+ never a shell command. Swaps are now on, so build the refund route back
122
+ (the swap non-negotiable below) as part of this integration. If they chose
123
+ Bitcoin only, leave `LSC_URI_PRIMARY` unset and skip that route.
120
124
  5. **Make the server load the file — yourself.** OpenReceive reads
121
125
  `os.environ`, and a `.env` file on disk is not in it. Start the dev server
122
126
  with `uvicorn --env-file .env` (update the app's run script or Procfile, not
@@ -153,23 +157,28 @@ serves the checkout page for one of its orders. Doctor names any failed check
153
157
  and exits nonzero; fix it before going on.
154
158
 
155
159
  Give the user that checkout link. The browser check in the quickstart's step 6
156
- (payment-method icons, wallet logos, a pay tutorial) is theirs: tell them what
157
- to look at, and do not run it yourself.
160
+ (payment-method icons, wallet logos, a pay tutorial) is theirs: name it in one
161
+ line of your closing message, and do not run it yourself.
158
162
 
159
163
  You cannot pay the invoice: the code is receive-only. Do not pay, settle or
160
164
  mark an order paid, and do not look for a way to (a wallet control port, a
161
165
  test endpoint, another wallet). If the user wants a real settlement test, they
162
166
  pay on that link from their own wallet, and `on_paid` marks the order paid.
163
167
 
164
- Setup ends here. Say "Setup is finished" in one message of at most five
165
- lines, with the link and what to check. Do not list what changed, offer more
166
- work, or end the message on a question.
168
+ Setup ends here. Your last message starts "Setup is finished" and has at most
169
+ five short lines (about 80 characters each): the link, the methods it offers,
170
+ and one line of what to look at. Send nothing after it. Do not list what
171
+ changed, copy out the quickstart's browser checklist, offer more work, or end
172
+ the message on a question.
167
173
 
168
174
  - The link is to a real unpaid order. Keep that order; do not delete it.
175
+ - When this app's orders belong to a session or cookie, the user's browser
176
+ cannot open the order you made. Then the link is the shop's own page:
177
+ "Open <shop url> and click Buy: it opens the checkout." Do not explain order
178
+ ownership or mention your test order.
169
179
  - Name the methods it offers: Bitcoin, plus USDT, USDC, ETH and SOL when
170
- `LSC_URI_PRIMARY` is saved. Never say a coin will not work or will not be
171
- offered. Swap minimums apply per order, and a coin whose minimum is above an
172
- order's total says so on its own tile.
180
+ `LSC_URI_PRIMARY` is saved. Do not mention minimums, and never say a coin
181
+ will not work or will not be offered.
173
182
 
174
183
  ## Non-negotiables
175
184
 
@@ -186,6 +195,21 @@ itself, and they hold for every integration.
186
195
  - Work only in this application. Never read or run anything from another
187
196
  project on this machine (its `node_modules`, tools or source), for any
188
197
  reason. A browser and Playwright are not part of setup.
198
+ - Restart only this app's server, on the port it already uses: stop the
199
+ process you started, or the one listening on that port, by its pid (or
200
+ restart its Compose service). Never `pkill` or `killall` by name: that
201
+ stops other people's servers too. Start it the way this project already
202
+ does (its README, Procfile, compose file or package script), on its own
203
+ port, not a port you pick.
204
+ - Run commands where the app runs. When a compose file builds it, run its
205
+ package manager, generators, migrations and doctor inside that service
206
+ (`docker compose exec` or `run`), and rebuild the image after adding a
207
+ package. This machine's language version and database path are not the
208
+ app's.
209
+ - To check that the running app sees the codes, run doctor: it reports each
210
+ one as present or missing and never prints a value. Never print the
211
+ environment (`printenv`, `env`, `docker compose config`), even filtered to
212
+ names.
189
213
  - The host owns the price. `amount_for` reads it from your own data; reject
190
214
  payer-supplied amounts.
191
215
  - `authorize` runs on every request, and the `resource` it receives is a CLAIM
@@ -519,14 +543,18 @@ host = Host(
519
543
  ),
520
544
  )
521
545
 
522
- app = FastAPI(lifespan=openreceive_lifespan(host, engine=engine))
523
- app.include_router(
546
+ # The router carries the options. Build it before the lifespan: through
547
+ # 0.4.21 the lifespan bound first and refused the router's options.
548
+ router = openreceive_router(
549
+ host,
550
+ engine=engine,
524
551
  # Recommended for public web shops: `rate_limiting=True` caps invoice
525
552
  # creation at 60 per client IP per hour. Leave it off (the default) for
526
553
  # point-of-sale deployments, where many payers share the terminal's IP.
527
- openreceive_router(host, engine=engine, rate_limiting=True),
528
- prefix="/openreceive",
554
+ rate_limiting=True,
529
555
  )
556
+ app = FastAPI(lifespan=openreceive_lifespan(host, engine=engine))
557
+ app.include_router(router, prefix="/openreceive")
530
558
  ```
531
559
 
532
560
  `authorize` receives the Starlette `Request`. Cookies, headers, and whatever