openreceive 0.4.13 → 0.4.15

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: 01e1bb860a7a293671cf05f57aab92369123dcade28a58bdb21c7c0917d3e53c
4
- data.tar.gz: ccdce9021e041361aa8340972fea01cdf4e762bcf4798903900185ec9535f63c
3
+ metadata.gz: 291e8df2ba4b159d4b5bede37b77df8449773110c8ec307f732e7f1f176df239
4
+ data.tar.gz: b81c08dd8358630ea628eb2d04cda593d1ba99e559612ffdffcaf9568c46f5e6
5
5
  SHA512:
6
- metadata.gz: 72862dc8a7059c13ff37db4261c4c6f37daaf2eba0e7bceebaf6cc2eeae8754938bb2aa853790856a0429922d6eff465d65f8e293759d9757c998b7b7060b107
7
- data.tar.gz: c3f5e0fc7c645e3a298579f29f926e1c33ee7bfa9fc5f764ef5e826d0905f34705439adde32156eb3758944dd14346ef18a50a4b315901683a3a512a056509e0
6
+ metadata.gz: a29c57a32d0e44750b4122d10e4c4bad8f451ca97dce0c8dfcbd5011e77666871d4d090bf1325e3bfc69fc74cabb815b217c15a836e62b6941a7b89ab02ded45
7
+ data.tar.gz: fd92160562d64c75466cb814419e1ca7bb781df453dfe275bae5d229595195f99b1be945c3e31070591834ad083f0fa07d54e9290557bbc3bf2be3bf9ead27e4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.15 - 2026-10-06
4
+
5
+ - Install agent skills with `bin/rails openreceive:skills` (optional
6
+ `--dir .claude/skills`). The core `openreceive` gem owns the one offline
7
+ bundle; Rails/server gems no longer duplicate it. Other Ruby hosts can use
8
+ `npx skills add OpenReceive/openreceive`.
9
+
10
+ `OpenReceive::Nwc.normalize_wallet_error` maps nwc-ruby 0.3's
11
+ `NotSentError`, `TransportError` and `InfoUnavailableError` to
12
+ `WALLET_UNAVAILABLE` (retryable) instead of `OTHER`, matching the shared
13
+ `error-normalization` vectors.
14
+
15
+ ## 0.4.14 - 2026-10-04
16
+
17
+ Release in lockstep with the 0.4.14 reconciliation fixes (in
18
+ `openreceive-rails`) and the plain-HTML refund documentation in the bundled
19
+ integration skill. No change to this gem's API.
20
+
3
21
  ## 0.4.13 - 2026-10-01
4
22
 
5
23
  Release in lockstep with the 0.4.13 reconciliation fixes (in
data/README.md CHANGED
@@ -74,3 +74,13 @@ cross-language vectors in `spec/test-vectors`.
74
74
  - Changelog: [CHANGELOG.md](CHANGELOG.md)
75
75
 
76
76
  MIT license.
77
+
78
+ ## Agent skills
79
+
80
+ In Rails, run `bin/rails openreceive:skills` from your application. The offline
81
+ skills ship once in the core `openreceive` gem. Non-Rails projects can use
82
+ `npx skills add OpenReceive/openreceive`.
83
+ See [agent setup](https://openreceive.org/agents). The bundled installers write
84
+ to `.agents/skills/`; use `--dir .claude/skills` for Claude Code. They replace
85
+ only `integrate-openreceive` and `debug-openreceive-payment`, preserving
86
+ unrelated skills.
@@ -316,6 +316,7 @@ module OpenReceive
316
316
  "EXPIRED" => "INVOICE_EXPIRED",
317
317
  "FETCH_ERROR" => "WALLET_UNAVAILABLE",
318
318
  "FORBIDDEN" => "RESTRICTED",
319
+ "INFO_UNAVAILABLE_ERROR" => "WALLET_UNAVAILABLE",
319
320
  "INVOICE_NOT_FOUND" => "NOT_FOUND",
320
321
  "INVALID_PARAMETER" => "INVALID_REQUEST",
321
322
  "INVALID_PARAMETERS" => "INVALID_REQUEST",
@@ -325,6 +326,7 @@ module OpenReceive
325
326
  "NIP47_NETWORK_ERROR" => "WALLET_UNAVAILABLE",
326
327
  "NOSTR_NETWORK_ERROR" => "WALLET_UNAVAILABLE",
327
328
  "NOT_AUTHORIZED" => "UNAUTHORIZED",
329
+ "NOT_SENT_ERROR" => "WALLET_UNAVAILABLE",
328
330
  "NOT_SUPPORTED" => "UNSUPPORTED_METHOD",
329
331
  "NOTFOUND" => "NOT_FOUND",
330
332
  "PERMISSION_DENIED" => "RESTRICTED",
@@ -333,6 +335,7 @@ module OpenReceive
333
335
  "SERVICE_UNAVAILABLE" => "WALLET_UNAVAILABLE",
334
336
  "TIMED_OUT" => "TIMEOUT",
335
337
  "TIMEOUT_ERROR" => "TIMEOUT",
338
+ "TRANSPORT_ERROR" => "WALLET_UNAVAILABLE",
336
339
  "UNKNOWN_METHOD" => "UNSUPPORTED_METHOD",
337
340
  "UNSUPPORTED" => "UNSUPPORTED_METHOD",
338
341
  "UNSUPPORTED_ENCRYPTION_MODE" => "UNSUPPORTED_ENCRYPTION",
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module OpenReceive
6
+ module Skills
7
+ def self.install(directory: ".agents/skills", output: $stdout)
8
+ source = File.join(Gem.loaded_specs.fetch("openreceive").full_gem_path, "skills")
9
+ target = File.expand_path(directory)
10
+ names = %w[integrate-openreceive debug-openreceive-payment]
11
+ names.each do |name|
12
+ raise "Bundled skill missing: #{name}. Reinstall openreceive." unless File.file?(File.join(source, name, "SKILL.md"))
13
+ end
14
+ FileUtils.mkdir_p(target)
15
+ target = File.realpath(target)
16
+ source = File.realpath(source)
17
+ if target == source || target.start_with?(source + File::SEPARATOR)
18
+ raise "Choose a skills directory outside the installed package's bundle."
19
+ end
20
+ names.each do |name|
21
+ destination = File.join(target, name)
22
+ FileUtils.rm_r(destination) if File.exist?(destination) || File.symlink?(destination)
23
+ FileUtils.cp_r(File.join(source, name), destination)
24
+ output.puts "Wrote #{destination}"
25
+ end
26
+ output.puts "For Claude Code: bin/rails openreceive:skills --dir .claude/skills"
27
+ 0
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenReceive
4
- VERSION = "0.4.13"
4
+ VERSION = "0.4.15"
5
5
  end
@@ -19,6 +19,12 @@ URL below is raw markdown — fetch it when the step needs it.
19
19
  npx openreceive doctor # Node version, NWC_URI, swap config, wallet probe
20
20
  npx openreceive doctor --db <db> # + are openreceive_payments/openreceive_meta migrated?
21
21
  npx openreceive doctor --url http://localhost:3000 # + are the routes actually mounted?
22
+ bin/rails openreceive:doctor # Rails
23
+ manage.py openreceive_doctor # Django
24
+ openreceive doctor --app main:app # FastAPI
25
+ php artisan openreceive:doctor # Laravel
26
+ wp openreceive doctor # WordPress
27
+ php bin/doctor # plain PHP: host script calling $engine->doctor()
22
28
  ```
23
29
 
24
30
  Each failing line states its own fix. `npx openreceive debug-report` prints the
@@ -32,7 +38,7 @@ same diagnostics redacted, always exit 0 — safe to share.
32
38
  | `INVALID_NWC` / "not a valid NWC code" | The value is malformed (must be `nostr+walletconnect://` with 64-hex pubkey and secret, ≥1 `wss` relay). Re-copy it from the wallet. |
33
39
  | "NOT receive-only" / spend methods advertised | The wallet minted a spend-capable code; OpenReceive fails closed because a leak would drain the wallet. Mint a receive-only code. Overriding (`allowSpendCapableWallet` / `OPENRECEIVE_ALLOW_SPEND_CAPABLE_NWC`) is a last resort. |
34
40
  | Wallet preflight failed (methods/encryption) | The wallet must advertise `make_invoice` + `list_transactions` and NIP-04 or NIP-44 v2. Use a compatible wallet. |
35
- | "The openreceive_meta table does not exist" / raw `no such table: openreceive_payments` | The migration was never applied. Node: `npx openreceive scaffold payments --orm <yours>`, then run the emitted migration through the app's normal workflow. Rails: `bin/rails generate openreceive:install`, then `bin/rails db:migrate`. https://openreceive.org/guides/storage.md |
41
+ | "The openreceive_meta table does not exist" / raw `no such table: openreceive_payments` | The migration was never applied. Node: `npx openreceive scaffold payments --orm <yours>`, then run the emitted migration through the app's normal workflow. Rails: `bin/rails generate openreceive:install`, then `bin/rails db:migrate`. Django: `manage.py openreceive_install <app> && manage.py migrate`. FastAPI: `openreceive scaffold payments --alembic --dialect <db>` (or `--sql`), then apply through the host workflow. Laravel: `php artisan openreceive:install && php artisan migrate`. Plain PHP: apply `OpenReceive\Storage\PaymentsSchema::statements($dialect)` through the host workflow. WordPress: check plugin activation/upgrades applied the tables. https://openreceive.org/guides/storage.md |
36
42
  | "requires amountFor / onPaid / authorize / host" | The factory is missing a required hook — see the host contract in https://openreceive.org/guides/api-reference.md |
37
43
 
38
44
  ## 3. Request-time errors from the routes
@@ -51,7 +57,12 @@ same diagnostics redacted, always exit 0 — safe to share.
51
57
  - Settlement is opportunistic: any OpenReceive request runs one reconcile pass
52
58
  through a durable gate (min 3s between wallet scans, stretched by invoice
53
59
  age). A quiet server settles on the next request — or run the optional
54
- notification worker. No timer is missing; that is the design.
60
+ notifications worker: Rails `bin/rails openreceive:notifications`, Django
61
+ `manage.py openreceive_notifications`, FastAPI
62
+ `openreceive notifications --app main:app`, Laravel
63
+ `php artisan openreceive:notifications`, WordPress `wp openreceive notifications`,
64
+ or plain PHP's host script `php bin/notifications`. Node hosts run their
65
+ separate worker using the notifications API. No web-process timer is missing.
55
66
  - An unpaid attempt closes only after a successful wallet scan at/after expiry
56
67
  plus a 900s grace constant — a local clock alone never closes one. `expired`
57
68
  arriving "late" is correct.
@@ -83,8 +94,13 @@ same diagnostics redacted, always exit 0 — safe to share.
83
94
 
84
95
  - The components require `prefix` — the exact base path the routes are mounted
85
96
  at (`"/openreceive"` unless you changed it).
86
- - Import the stylesheet (`@openreceive/react/styles.css` or the elements
87
- sheet).
97
+ - Import `@openreceive/react/styles.css` or `@openreceive/elements/styles.css`
98
+ alongside the component registration. For standalone Django/Laravel/PHP,
99
+ serve both `openreceive-checkout.js` (as a module) and
100
+ `openreceive-checkout.css`. Django serves them from `static/openreceive/`
101
+ via `collectstatic`; Laravel/PHP serve the unpacked standalone assets from
102
+ the public directory. Check that both requests succeed and the custom
103
+ element is registered. Do not process the compiled stylesheet with Tailwind.
88
104
  - "invoice must not be an NWC connection string" means a server secret leaked
89
105
  into a browser payload — stop and fix the server response; never render it.
90
106
  https://openreceive.org/guides/frontend-checkout.md
@@ -1,12 +1,13 @@
1
1
  ---
2
2
  name: integrate-openreceive
3
3
  description: >
4
- Integrate OpenReceive inbound Bitcoin Lightning payments into an application.
5
- Use when adding Bitcoin, Lightning, or crypto checkout to a Node.js, Express,
6
- Fastify, Next.js, Rails, React, Vue, Svelte, Angular, or plain-HTML
7
- application with OpenReceive (the @openreceive/* npm packages or the
8
- openreceive-rails gem), or when connecting a BTCPay Server store to a
9
- receive-only NWC wallet with the OpenReceive plugin.
4
+ Integrate OpenReceive Bitcoin Lightning checkout and optional USDT, USDC,
5
+ SOL, and ETH swaps. Use for Node.js, Express, Fastify, Next.js, Rails,
6
+ Python, Django, FastAPI, Laravel, plain PHP, WordPress/WooCommerce,
7
+ React, Vue, Svelte, Angular, or plain HTML applications, or connecting
8
+ BTCPay Server to a receive-only NWC wallet. A configured swap provider
9
+ converts these payments to BTC over Lightning in the merchant's connected
10
+ wallet; asset and network availability depends on the provider.
10
11
  license: MIT
11
12
  ---
12
13
 
@@ -19,6 +20,10 @@ settles. There is no OpenReceive account and no API key; funds land directly in
19
20
  the merchant's wallet. The one required credential is a **receive-only NWC
20
21
  code** (`NWC_URI`).
21
22
 
23
+ Optional swaps let customers pay with USDT, USDC, SOL, and ETH. A configured
24
+ swap provider converts these payments to BTC over Lightning in the merchant's
25
+ connected wallet; asset and network availability depends on the provider.
26
+
22
27
  ## Pick the stack, then follow its directions
23
28
 
24
29
  1. Identify the server stack of the application you are in.
@@ -28,6 +33,8 @@ code** (`NWC_URI`).
28
33
  - Node, Fastify: [references/fastify.md](references/fastify.md)
29
34
  - Node, Next.js App Router: [references/next.md](references/next.md)
30
35
  - Rails: [references/rails.md](references/rails.md)
36
+ - Python, FastAPI: [references/fastapi.md](references/fastapi.md)
37
+ - Plain PHP: [references/php.md](references/php.md)
31
38
  - Django: [references/django.md](references/django.md)
32
39
  - Laravel: [references/laravel.md](references/laravel.md)
33
40
  - WordPress + WooCommerce: [references/woocommerce.md](references/woocommerce.md) — the packaged gateway and merchant settings.
@@ -44,6 +51,9 @@ Fastify: `npm install @openreceive/fastify @openreceive/react`; Next.js:
44
51
  `npm install @openreceive/next @openreceive/react`. Swap the UI package (`vue`,
45
52
  `svelte`, `angular`, `elements`) for the frontend the app already has. Install
46
53
  (Rails): `bundle add openreceive-rails`.
54
+ Django: `pip install "openreceive[django]"`; FastAPI:
55
+ `pip install "openreceive[fastapi]"`; Laravel: `composer require openreceive/laravel`;
56
+ plain PHP: `composer require openreceive/openreceive nyholm/psr7 nyholm/psr7-server`.
47
57
 
48
58
  ## The three server objects
49
59
 
@@ -108,25 +118,36 @@ overriding.
108
118
 
109
119
  ## Database tables
110
120
 
111
- ```sh
112
- npx openreceive scaffold payments --orm prisma # or drizzle | typeorm | sequelize | knex
113
- ```
121
+ Generate the two tables in the host's existing database:
114
122
 
115
- emits the `openreceive_payments` + `openreceive_meta` migration for THIS app's
116
- database (Rails: `bin/rails generate openreceive:install`); run it through the
117
- app's normal migration workflow. The tables sit beside your models — no
118
- relations to them, no separate database, no Redis.
123
+ | Stack | Generate and apply |
124
+ | --- | --- |
125
+ | Node | `npx openreceive scaffold payments --orm <orm>`, then the app's normal migration command |
126
+ | Rails | `bin/rails generate openreceive:install && bin/rails db:migrate` |
127
+ | Django | `manage.py openreceive_install <app> && manage.py migrate` |
128
+ | FastAPI | `openreceive scaffold payments --alembic --dialect <db>` (or `--sql`), then apply through the app's migration workflow |
129
+ | Laravel | `php artisan openreceive:install && php artisan migrate` |
130
+ | Plain PHP | Use `OpenReceive\Storage\PaymentsSchema::statements($dialect)` in the host's migration workflow, as in the PHP reference |
119
131
 
120
- ## Verify, and test without a real wallet
132
+ These emit `openreceive_payments` + `openreceive_meta`. The tables sit beside
133
+ your models — no relations to them, no separate database, no Redis. WordPress
134
+ and BTCPay manage installation through their plugins; follow their references.
121
135
 
122
- `npx openreceive doctor` checks the configuration and says what to fix.
136
+ ## Verify, and test without a real wallet
123
137
 
124
- For tests, inject a fake wallet at the stable seams — `client` on
125
- `createOpenReceive` (any object with `preflight`, `makeInvoice`,
126
- `listTransactions`) or `config.nwc_client` in Rails — plus
127
- `StaticPriceProvider` for fiat pricing without a network. Your routes,
128
- persistence, reconcile, and `onPaid` then run the production code paths.
129
- Details: https://openreceive.org/guides/host-testing.md
138
+ | Stack | Doctor | Test seam |
139
+ | --- | --- | --- |
140
+ | Node | `npx openreceive doctor` | `client` on `createOpenReceive` (`preflight`, `makeInvoice`, `listTransactions`), plus `StaticPriceProvider` |
141
+ | Rails | `bin/rails openreceive:doctor` | `config.nwc_client`, `config.swap_providers`, `config.price_provider` |
142
+ | Django | `manage.py openreceive_doctor` | `OPENRECEIVE["SERVICE"]`, a factory returning a `Service` built on `openreceive.testing` fakes |
143
+ | FastAPI | `openreceive doctor --app main:app` | `nwc_client`, `price_provider`, `swap_providers` on `openreceive_router`, using `openreceive.testing` fakes |
144
+ | Laravel | `php artisan openreceive:doctor` | Bind `ReceiveNwcClient`, `PriceProvider`, and `OpenReceiveServiceProvider::SWAP_PROVIDERS` in the container |
145
+ | Plain PHP | `php bin/doctor` (host script calling `$engine->doctor()`) | Build `Service` with `OpenReceive\Testing\FakeWallet`, `FakeSwapProvider`, and `OpenReceive\Rates\StaticPriceProvider` |
146
+ | WordPress | `wp openreceive doctor` | Repository development: the documented Docker `compose.testkit.yml` override |
147
+ | BTCPay | Follow the plugin reference's connection and checkout checks | Use the plugin's Docker test setup in its reference |
148
+
149
+ The routes, persistence, reconciliation, and fulfillment hooks then run the
150
+ production paths. Details: https://openreceive.org/guides/host-testing.md
130
151
 
131
152
  ## Deeper documentation
132
153
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (BTCPay Server)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Connect a BTCPay Server store to a receive-only NWC wallet with the OpenReceive
6
6
  plugin, and optionally let payers pay BTCPay invoices with USDT, USDC, ETH or
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Django)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a Django project — the app you are already working in. You
6
6
  do not need a copy of the OpenReceive source: the Python package is on PyPI
@@ -167,15 +167,19 @@ itself, and they hold for every integration.
167
167
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
168
168
  after leaving your page to fetch an address from another wallet. Three things
169
169
  must exist or that money is unreachable through your UI: a per-order URL your
170
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
171
- order-summary route to restore the order from, and the ATTEMPT.
170
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
171
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
172
+ restore the order from, and the ATTEMPT.
172
173
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
173
174
  reference alone opens on the method grid. Re-picking the same coin
174
175
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
175
176
  and the shadow invoice behind a swap lasts about half an hour, after which the
176
177
  same click mints a NEW deposit address and the refund is off-screen. Keep the
177
178
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
178
- such window. https://openreceive.org/guides/swap-refunds.md
179
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
180
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
181
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
182
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
179
183
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
180
184
  the price from `amount_for` and both drop-ins render it above the
181
185
  amount. Without it the checkout is a QR and "$1.00" with no sign of what the
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (FastAPI)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a FastAPI application — the app you are already working in.
6
6
  You do not need a copy of the OpenReceive source: the engine is on PyPI
@@ -157,15 +157,19 @@ itself, and they hold for every integration.
157
157
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
158
158
  after leaving your page to fetch an address from another wallet. Three things
159
159
  must exist or that money is unreachable through your UI: a per-order URL your
160
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
161
- order-summary route to restore the order from, and the ATTEMPT.
160
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
161
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
162
+ restore the order from, and the ATTEMPT.
162
163
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
163
164
  reference alone opens on the method grid. Re-picking the same coin
164
165
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
165
166
  and the shadow invoice behind a swap lasts about half an hour, after which the
166
167
  same click mints a NEW deposit address and the refund is off-screen. Keep the
167
168
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
168
- such window. https://openreceive.org/guides/swap-refunds.md
169
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
170
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
171
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
172
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
169
173
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
170
174
  the price from `amount_for` and both drop-ins render it above the amount.
171
175
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Fastify)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a Fastify application — the app you are already working in.
6
6
  You do not need a copy of the OpenReceive source: the packages are on npm, and
@@ -149,15 +149,19 @@ itself, and they hold for every integration.
149
149
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
150
150
  after leaving your page to fetch an address from another wallet. Three things
151
151
  must exist or that money is unreachable through your UI: a per-order URL your
152
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
153
- order-summary route to restore the order from, and the ATTEMPT.
152
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
153
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
154
+ restore the order from, and the ATTEMPT.
154
155
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
155
156
  reference alone opens on the method grid. Re-picking the same coin
156
157
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
157
158
  and the shadow invoice behind a swap lasts about half an hour, after which the
158
159
  same click mints a NEW deposit address and the refund is off-screen. Keep the
159
160
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
160
- such window. https://openreceive.org/guides/swap-refunds.md
161
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
162
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
163
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
164
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
161
165
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
162
166
  the price from `amountFor` and both drop-ins render it above the amount.
163
167
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -375,7 +379,9 @@ there is nothing else to generate. Details:
375
379
  No ORM? You can pass a bare driver handle (`pg`, `node:sqlite`,
376
380
  `better-sqlite3`) as the `db` in step 4. The scaffold has no flavor for it.
377
381
  Instead of scaffolding, run the same DDL once yourself, using
378
- `paymentsSchemaSql(dialect)` from `@openreceive/http`.
382
+ `paymentsSchemaSql(dialect)` from `@openreceive/http`. Your adapter already
383
+ pulls that package in, but this import is yours, so install it too:
384
+ `npm install @openreceive/http`.
379
385
 
380
386
  ### 3. Add wallet credentials
381
387
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Laravel)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a Laravel application — the app you are already working in.
6
6
  You do not need a copy of the OpenReceive source: the package is on Packagist
@@ -158,15 +158,19 @@ itself, and they hold for every integration.
158
158
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
159
159
  after leaving your page to fetch an address from another wallet. Three things
160
160
  must exist or that money is unreachable through your UI: a per-order URL your
161
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
162
- order-summary route to restore the order from, and the ATTEMPT.
161
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
162
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
163
+ restore the order from, and the ATTEMPT.
163
164
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
164
165
  reference alone opens on the method grid. Re-picking the same coin
165
166
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
166
167
  and the shadow invoice behind a swap lasts about half an hour, after which the
167
168
  same click mints a NEW deposit address and the refund is off-screen. Keep the
168
169
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
169
- such window. https://openreceive.org/guides/swap-refunds.md
170
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
171
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
172
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
173
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
170
174
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
171
175
  the price from `amountFor` and both drop-ins render it above the
172
176
  amount. Without it the checkout is a QR and "$1.00" with no sign of what the
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Next.js)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a Next.js App Router application — the app you are already
6
6
  working in. You do not need a copy of the OpenReceive source: the packages are
@@ -149,15 +149,19 @@ itself, and they hold for every integration.
149
149
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
150
150
  after leaving your page to fetch an address from another wallet. Three things
151
151
  must exist or that money is unreachable through your UI: a per-order URL your
152
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
153
- order-summary route to restore the order from, and the ATTEMPT.
152
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
153
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
154
+ restore the order from, and the ATTEMPT.
154
155
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
155
156
  reference alone opens on the method grid. Re-picking the same coin
156
157
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
157
158
  and the shadow invoice behind a swap lasts about half an hour, after which the
158
159
  same click mints a NEW deposit address and the refund is off-screen. Keep the
159
160
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
160
- such window. https://openreceive.org/guides/swap-refunds.md
161
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
162
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
163
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
164
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
161
165
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
162
166
  the price from `amountFor` and both drop-ins render it above the amount.
163
167
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -381,7 +385,9 @@ there is nothing else to generate. Details:
381
385
  No ORM? You can pass a bare driver handle (`pg`, `node:sqlite`,
382
386
  `better-sqlite3`) as the `db` in step 4. The scaffold has no flavor for it.
383
387
  Instead of scaffolding, run the same DDL once yourself, using
384
- `paymentsSchemaSql(dialect)` from `@openreceive/http`.
388
+ `paymentsSchemaSql(dialect)` from `@openreceive/http`. Your adapter already
389
+ pulls that package in, but this import is yours, so install it too:
390
+ `npm install @openreceive/http`.
385
391
 
386
392
  ### 3. Add wallet credentials
387
393
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Node.js)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a Node application — the app you are already working in. You
6
6
  do not need a copy of the OpenReceive source: the packages are on npm, and the
@@ -146,15 +146,19 @@ itself, and they hold for every integration.
146
146
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
147
147
  after leaving your page to fetch an address from another wallet. Three things
148
148
  must exist or that money is unreachable through your UI: a per-order URL your
149
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
150
- order-summary route to restore the order from, and the ATTEMPT.
149
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
150
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
151
+ restore the order from, and the ATTEMPT.
151
152
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
152
153
  reference alone opens on the method grid. Re-picking the same coin
153
154
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
154
155
  and the shadow invoice behind a swap lasts about half an hour, after which the
155
156
  same click mints a NEW deposit address and the refund is off-screen. Keep the
156
157
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
157
- such window. https://openreceive.org/guides/swap-refunds.md
158
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
159
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
160
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
161
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
158
162
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
159
163
  the price from `amountFor` and both drop-ins render it above the amount.
160
164
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -366,7 +370,9 @@ there is nothing else to generate. Details:
366
370
  No ORM? You can pass a bare driver handle (`pg`, `node:sqlite`,
367
371
  `better-sqlite3`) as the `db` in step 4. The scaffold has no flavor for it.
368
372
  Instead of scaffolding, run the same DDL once yourself, using
369
- `paymentsSchemaSql(dialect)` from `@openreceive/http`.
373
+ `paymentsSchemaSql(dialect)` from `@openreceive/http`. Your adapter already
374
+ pulls that package in, but this import is yours, so install it too:
375
+ `npm install @openreceive/http`.
370
376
 
371
377
  ### 3. Add wallet credentials
372
378
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (PHP)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a PHP application — the app you are already working in. You
6
6
  do not need a copy of the OpenReceive source: the engine is on Packagist
@@ -171,7 +171,9 @@ itself, and they hold for every integration.
171
171
  and the shadow invoice behind a swap lasts about half an hour, after which the
172
172
  same click mints a NEW deposit address and the refund is off-screen. Keep the
173
173
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
174
- such window. https://openreceive.org/guides/swap-refunds.md
174
+ such window. On the element: the `resume-payment-hash` attribute, fed from
175
+ the `openreceive-state` event (`event.detail.state.payment_hash`).
176
+ https://openreceive.org/guides/swap-refunds.md
175
177
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
176
178
  the price from `amountFor` and the drop-in renders it above the amount.
177
179
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Rails)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Add OpenReceive to a Rails application — the app you are already working in. You
6
6
  do not need a copy of the OpenReceive source: the gem is on RubyGems, the
@@ -153,15 +153,19 @@ itself, and they hold for every integration.
153
153
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
154
154
  after leaving your page to fetch an address from another wallet. Three things
155
155
  must exist or that money is unreachable through your UI: a per-order URL your
156
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
157
- order-summary route to restore the order from, and the ATTEMPT.
156
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
157
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
158
+ restore the order from, and the ATTEMPT.
158
159
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
159
160
  reference alone opens on the method grid. Re-picking the same coin
160
161
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
161
162
  and the shadow invoice behind a swap lasts about half an hour, after which the
162
163
  same click mints a NEW deposit address and the refund is off-screen. Keep the
163
164
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
164
- such window. https://openreceive.org/guides/swap-refunds.md
165
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
166
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
167
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
168
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
165
169
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
166
170
  the price from `config.amount_for` and both drop-ins render it above the
167
171
  amount. Without it the checkout is a QR and "$1.00" with no sign of what the
@@ -1,23 +1,53 @@
1
1
  # OpenReceive agent directions (WordPress + WooCommerce)
2
2
 
3
- These directions describe OpenReceive 0.4.13.
3
+ These directions describe OpenReceive 0.4.15.
4
4
 
5
5
  Install and configure the OpenReceive gateway in the existing WooCommerce
6
6
  store. Preserve its theme, checkout, customer accounts, order model and prices.
7
7
  The plugin bundles the PHP engine and checkout assets; the merchant does not
8
8
  install npm or Composer packages on the WordPress server.
9
9
 
10
- ## Step 0 — inspect configuration
10
+ ## Step 0 — collect and save the codes, one at a time
11
11
 
12
- Check WordPress, WooCommerce and PHP versions, GMP and sodium availability,
13
- whether the plugin is installed, and whether the Doctor panel reports the
14
- receive-only NWC credential as set. Never display its value. For a real store,
15
- ask the merchant to configure a receive-only wallet if none is available.
16
- For repository development, use the Docker demo's explicit testkit override.
12
+ Inspect WordPress, WooCommerce and PHP versions and GMP/sodium in both the web
13
+ and WP-CLI runtimes. If installed, use `wp openreceive doctor` to see which
14
+ credentials are set, without displaying their values. Skip codes already set.
15
+ Do not search other projects, container environments or deployment secrets.
17
16
 
18
- Upload a built plugin archive, not a zip of the source directory. The plugin
19
- has not yet been accepted into the WordPress.org directory. Configuration and
20
- the complete quickstart follow below.
17
+ Ask for the missing receive-only NWC code first, with this walkthrough:
18
+
19
+ > In Rizful, open the menu → NWC → Receive-only NWC code → Copy
20
+ > (https://openreceive.org/get_a_nwc_code_to_receive_payments). Alby Hub also
21
+ > works: Connections → Add Connection → Read Only. Paste the code here and
22
+ > I will save it for you.
23
+
24
+ Install the exact built plugin archive described below if needed. When the code
25
+ arrives, save it yourself with `wp openreceive configure --nwc-uri=-`, supplying
26
+ the code through the process's stdin. Never put it in shell arguments, shell
27
+ history, logs, source files or browser code. Do not ask the user to edit PHP or
28
+ an environment file. The command encrypts the code and runs wallet preflight
29
+ before saving; a failure preserves existing settings. Constants in wp-config.php
30
+ remain authoritative; if a constant must change, use the host's secret workflow.
31
+
32
+ Next ask whether customers should also pay with USDT, USDC, SOL and ETH, unless
33
+ the user already requested these. A configured swap provider converts payments
34
+ to BTC over Lightning in the merchant's connected wallet; available assets and
35
+ networks depend on the provider. Ask for the LSC code separately:
36
+
37
+ > Go to https://lightning-swap.com, sign in for API keys, create a key, and copy
38
+ > the whole URI (https://openreceive.org/set_up_swap_provider). Paste it here
39
+ > and I will save it, or say “Bitcoin only”.
40
+
41
+ Save it with `wp openreceive configure --lsc-uri-primary=-` through stdin.
42
+ Mention FixedFloat only if the merchant already uses it. Save an optional backup
43
+ separately with `--lsc-uri-backup=-`. Do not use generic `wp wc payment_gateway`
44
+ or REST settings writes for credentials: they are deliberately rejected.
45
+
46
+ Run `wp openreceive configure --enable`, then `wp openreceive doctor`. Resolve
47
+ failed checks before checkout testing. Create an unpaid test order and verify
48
+ that the order-pay page opens, lists the configured methods, and resumes its
49
+ Lightning invoice on reload. Ask the merchant to pay only if they want a real
50
+ settlement test.
21
51
 
22
52
  The plugin owns only its payment-attempt tables in the WordPress database.
23
53
  WooCommerce owns orders, totals, stock and email. Do not add an external
@@ -32,48 +62,13 @@ flows; a receive-only NWC wallet cannot send payments.
32
62
 
33
63
  ## Further reading
34
64
 
35
- - [Express Quickstart (Node)](https://openreceive.org/guides/quickstart-node.md)
36
- - [Fastify Quickstart](https://openreceive.org/guides/quickstart-fastify.md)
37
- - [FastAPI Quickstart](https://openreceive.org/guides/quickstart-fastapi.md)
38
- - [Django Quickstart](https://openreceive.org/guides/quickstart-django.md)
39
- - [Next.js Quickstart](https://openreceive.org/guides/quickstart-next.md)
40
- - [Rails Quickstart](https://openreceive.org/guides/quickstart-rails.md)
41
- - [PHP Quickstart (plain PHP)](https://openreceive.org/guides/quickstart-php.md)
42
- - [Laravel Quickstart](https://openreceive.org/guides/quickstart-laravel.md)
43
- - [BTCPay Server Quickstart](https://openreceive.org/guides/quickstart-btcpay.md)
44
- - [BTCPay Plugin Reference](https://openreceive.org/guides/btcpay-reference.md)
45
- - [Node ORM Recipes](https://openreceive.org/guides/node-orms.md)
46
- - [Authorization](https://openreceive.org/guides/authorization.md)
47
- - [Rate Limiting](https://openreceive.org/guides/rate-limiting.md)
48
- - [Frontend Checkout](https://openreceive.org/guides/frontend-checkout.md)
49
- - [Checkout UX](https://openreceive.org/guides/checkout-ux.md)
50
- - [Headless Checkout](https://openreceive.org/guides/headless-checkout.md)
65
+ - [WordPress + WooCommerce Quickstart](https://openreceive.org/guides/quickstart-woocommerce.md)
51
66
  - [Automated Swaps](https://openreceive.org/guides/automated-swaps.md)
52
67
  - [Swap Refunds](https://openreceive.org/guides/swap-refunds.md)
53
68
  - [Lightning Swap Connect URI](https://openreceive.org/guides/lightning-swap-connect.md)
54
- - [Environment Variables](https://openreceive.org/guides/environment-variables.md)
55
- - [Payment Storage](https://openreceive.org/guides/storage.md)
56
- - [Deploying OpenReceive](https://openreceive.org/guides/deploying.md)
57
- - [Testing Your OpenReceive Integration](https://openreceive.org/guides/host-testing.md)
58
- - [API Reference](https://openreceive.org/guides/api-reference.md)
59
69
  - [Security](https://openreceive.org/guides/security.md)
60
- - [Provider Registry](https://openreceive.org/guides/provider-registry.md)
61
70
  - [Price Feeds](https://openreceive.org/guides/price-feeds.md)
62
- - [React Material UI Recipe](https://openreceive.org/guides/react-material-ui-recipe.md)
63
- - [Flask Recipe](https://openreceive.org/guides/flask-recipe.md)
64
- - [Writing Your Own Checkout Route](https://openreceive.org/guides/custom-checkout-route.md)
65
- - [Agent Directions: Node.js](https://openreceive.org/guides/agent-directions-node.md)
66
- - [Agent Directions: Fastify](https://openreceive.org/guides/agent-directions-fastify.md)
67
- - [Agent Directions: FastAPI](https://openreceive.org/guides/agent-directions-fastapi.md)
68
- - [Agent Directions: Django](https://openreceive.org/guides/agent-directions-django.md)
69
- - [Agent Directions: Next.js](https://openreceive.org/guides/agent-directions-next.md)
70
- - [Agent Directions: Rails](https://openreceive.org/guides/agent-directions-rails.md)
71
- - [Agent Directions: PHP](https://openreceive.org/guides/agent-directions-php.md)
72
- - [Agent Directions: Laravel](https://openreceive.org/guides/agent-directions-laravel.md)
73
- - [Agent Directions: BTCPay Server](https://openreceive.org/guides/agent-directions-btcpay.md)
74
- - [WordPress + WooCommerce Quickstart](https://openreceive.org/guides/quickstart-woocommerce.md)
75
-
76
- - https://openreceive.org/guides/payment-safety-upgrade.md — coordinated upgrades and reviewed repair of existing attempts
71
+ - [Payment Safety Upgrade](https://openreceive.org/guides/payment-safety-upgrade.md)
77
72
 
78
73
  ---
79
74
 
@@ -84,6 +79,10 @@ passes. The page it comes from is https://openreceive.org/guides/quickstart-wooc
84
79
 
85
80
  ## WordPress + WooCommerce quickstart
86
81
 
82
+ The [WordPress integration entry point](https://openreceive.org/integrations/wordpress)
83
+ redirects to the WooCommerce integration, which uses this same guide and agent
84
+ directions. OpenReceive checkout on WordPress requires WooCommerce.
85
+
87
86
  Activate WooCommerce first. Then install the built OpenReceive plugin zip
88
87
  through **Plugins → Add New → Upload Plugin**. You cannot upload the source
89
88
  directory as-is. It needs a build first. The plugin is not yet submitted to
@@ -96,15 +95,16 @@ database or application.
96
95
 
97
96
  ### Get the installable archive
98
97
 
99
- If the [OpenReceive GitHub release](https://github.com/OpenReceive/openreceive/releases)
100
- you picked lists `openreceive-wordpress-<version>.zip`, use that file. The GitHub
101
- source-code zip is not the plugin archive. If the release has no built zip yet,
102
- build one on a development machine with Node 22+, PHP 8.2+, Composer and WP-CLI:
98
+ Download [openreceive-wordpress-0.4.15.zip](https://github.com/OpenReceive/openreceive/releases/download/v0.4.15/openreceive-wordpress-0.4.15.zip)
99
+ from the matching release. Historical releases may lack this asset. If that exact
100
+ URL returns 404, build the same tag below; never silently install an older ZIP.
101
+ The GitHub source-code ZIP is not an installable plugin. On a development machine
102
+ with Node 22+, PHP 8.2+ with GMP/sodium, Composer and WP-CLI:
103
103
 
104
104
  ```sh
105
105
  git clone https://github.com/OpenReceive/openreceive.git
106
106
  cd openreceive
107
- git checkout <release-tag>
107
+ git checkout v0.4.15
108
108
  npm ci
109
109
  npm run build:packages
110
110
  composer install --working-dir=packages/php/wordpress
@@ -116,6 +116,40 @@ needs WP-CLI on `PATH`. Otherwise, set `OPENRECEIVE_WP_CLI` to the absolute path
116
116
  of its phar. Your WordPress server needs neither Node nor Composer. The built
117
117
  plugin already bundles its dependencies and checkout assets.
118
118
 
119
+ ### Enable GMP in both PHP runtimes
120
+
121
+ GMP is required by the bundled elliptic-curve dependency. Enable it for both
122
+ web PHP (Apache/FPM) and the PHP executable running WP-CLI. Installing it in
123
+ only the WordPress container does not update a separate CLI container.
124
+
125
+ For Debian-based official PHP/WordPress images, add to **each** Dockerfile:
126
+
127
+ ```dockerfile
128
+ USER root
129
+ RUN apt-get update && apt-get install -y --no-install-recommends libgmp-dev \
130
+ && docker-php-ext-install gmp \
131
+ && rm -rf /var/lib/apt/lists/*
132
+ ```
133
+
134
+ For Alpine-based PHP/CLI images:
135
+
136
+ ```dockerfile
137
+ USER root
138
+ RUN apk add --no-cache gmp \
139
+ && apk add --no-cache --virtual .gmp-build $PHPIZE_DEPS gmp-dev \
140
+ && docker-php-ext-install gmp \
141
+ && apk del .gmp-build
142
+ ```
143
+
144
+ Restore the base image's original runtime user after installing extensions.
145
+ Rebuild and recreate both containers. On Debian/Ubuntu hosts, install the GMP
146
+ package matching the active PHP version (for example `php8.2-gmp` for PHP 8.2),
147
+ then restart that version's web PHP service. Verify `php --ri gmp` and
148
+ `wp openreceive doctor` for CLI, and the gateway Doctor panel for web PHP.
149
+ On managed WordPress hosting, ask the host to enable GMP and sodium in both
150
+ runtimes; if they cannot, this plugin cannot run there. Do not use Composer's
151
+ `--ignore-platform-reqs` to bypass the requirements.
152
+
119
153
  ### Configure the wallet
120
154
 
121
155
  1. Open **WooCommerce → Settings → Payments → OpenReceive**.
@@ -134,6 +168,27 @@ providers, you can also set the `OPENRECEIVE_LSC_URI_PRIMARY` and
134
168
  `OPENRECEIVE_LSC_URI_BACKUP` constants. Never put these values in browser code
135
169
  or logs.
136
170
 
171
+ #### Configure through WP-CLI
172
+
173
+ `wp openreceive configure` accepts one credential at a time from stdin. Feed
174
+ stdin through your secret manager or an existing protected file, never a code
175
+ literal in the command line:
176
+
177
+ ```sh
178
+ wp openreceive configure --nwc-uri=- < /secure/path/wallet-code
179
+ wp openreceive configure --lsc-uri-primary=- < /secure/path/swap-code
180
+ wp openreceive configure --enable
181
+ wp openreceive doctor
182
+ ```
183
+
184
+ Omit the swap command for Bitcoin-only checkout. `--lsc-uri-backup=-` adds a
185
+ backup. These commands share admin preflight and encrypted storage. Credential
186
+ flags accept only `-`; blank input leaves settings intact. Generic WooCommerce
187
+ REST and `wp wc payment_gateway` credential updates are rejected. `doctor`
188
+ reports the failed check with credentials redacted and exits nonzero on failure.
189
+ The default payment title becomes “Bitcoin & crypto (OpenReceive)” with swaps;
190
+ a customized title is preserved.
191
+
137
192
  ### Checkout and settlement
138
193
 
139
194
  Both WooCommerce checkout blocks and classic checkout send the customer to the
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openreceive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.13
4
+ version: 0.4.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenReceive
@@ -51,6 +51,7 @@ files:
51
51
  - lib/openreceive/keccak256.rb
52
52
  - lib/openreceive/nwc_ruby.rb
53
53
  - lib/openreceive/rates.rb
54
+ - lib/openreceive/skills.rb
54
55
  - lib/openreceive/swap_address.rb
55
56
  - lib/openreceive/version.rb
56
57
  - skills/debug-openreceive-payment/SKILL.md