@openreceive/http 0.4.3 → 0.4.6

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.
package/README.md CHANGED
@@ -1,13 +1,35 @@
1
1
  # @openreceive/http
2
2
 
3
- Framework-neutral receive-checkout handler. Its normal form requires `service`,
4
- `authorize`, and the `host` integration. Create bodies never accept payer
5
- amounts; the host's `amountFor` hook is the only price authority, and the
6
- commit hook appends a payment-attempt row before the invoice is returned.
3
+ Add Bitcoin Lightning checkout to your Node.js application while keeping
4
+ your orders, prices, and fulfillment in your own code. This package provides
5
+ the Web Request/Response handler and payment repository used by the Express,
6
+ Fastify, and Next.js adapters, with payment attempts stored in your existing
7
+ database.
8
+
9
+ OpenReceive supports optional swaps from **USDT, USDC, SOL, and ETH** through
10
+ a configured swap provider. The provider converts the payment to **BTC over
11
+ Lightning**, which settles into the merchant's connected wallet. Available
12
+ assets and networks depend on the provider; swaps are optional.
13
+
14
+ ## Install
7
15
 
8
16
  This package is ESM-only and requires Node >= 22.
9
17
 
10
- `createHost({ db, amountFor, onPaid })` builds that
18
+ ```sh
19
+ npm install @openreceive/http
20
+ ```
21
+
22
+ Start with the [integration quickstart](https://github.com/openreceive/openreceive/blob/master/docs/guides/quickstart-node.md)
23
+ and the [payment storage guide](https://github.com/openreceive/openreceive/blob/master/docs/guides/storage.md).
24
+
25
+ ## Connect your application
26
+
27
+ For Express, Fastify, or Next.js, start with the matching adapter; each uses
28
+ this handler and repository. For a custom Node.js host, compose `service`,
29
+ `authorize`, and the `host` integration. Amounts come from your server, and
30
+ a payment attempt is committed before checkout instructions are returned.
31
+
32
+ `createHost({ db, amountFor, onPaid })` builds the
11
33
  host integration on the library-owned payment repository inside the host
12
34
  application's existing database (pg, node:sqlite, better-sqlite3, or a custom
13
35
  adapter). The library owns attempt selection, per-reference commit locking,
@@ -54,4 +76,5 @@ here (`npm run check:public-api` pins both surfaces):
54
76
  `WirePaymentCheck`, `WireError`, …), generated from the
55
77
  OpenAPI contract. The adapters re-export these too.
56
78
 
57
- See the root README, the storage guide, and the OpenAPI contract.
79
+ See the [API reference](https://github.com/openreceive/openreceive/blob/master/docs/guides/api-reference.md)
80
+ and [HTTP contract](https://github.com/openreceive/openreceive/blob/master/spec/openapi/openreceive-http.v1.yaml).
@@ -110,12 +110,6 @@ declare function jsonResponse(status: number, body: unknown, requestId: string,
110
110
  */
111
111
  declare function errorResponse(error: unknown, requestId: string): Response;
112
112
 
113
- /**
114
- * Seconds past an attempt's expiry during which reconciliation still scans for a
115
- * settlement before closing the attempt. Covers clock skew and wallets that
116
- * accept a payment moments after nominal invoice expiry.
117
- */
118
- declare const OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS: 900;
119
113
  /**
120
114
  * Lifecycle of one payment attempt: {@link TransactionSettlementStatus} plus
121
115
  * `attention`. `pending` attempts participate in reconciliation; every other
@@ -741,4 +735,4 @@ declare function createStack(options: CreateStackOptions): Stack;
741
735
  */
742
736
  declare function isStackOptions(options: CreateHttpHandlerOptions | CreateStackOptions): options is CreateStackOptions;
743
737
 
744
- export { errorResponse as $, type AttemptStatus as A, type SettlementEvent as B, type CheckoutCreatedHook as C, type SettlementEventHook as D, type SettlementRecord as E, type SqlClient as F, type SqlDatabase as G, type Host as H, type IpRateLimitConfig as I, type SqlPaymentRepository as J, type SqlPaymentsOptions as K, type SqlQuery as L, type Stack as M, type NotificationListener as N, OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS as O, type PaymentInsert as P, type StackStorage as Q, type ReconcilableAttempt as R, type SqlAdapter as S, type StackWallet as T, createHost as U, createHttpHandler as V, createIpRateLimit as W, createProxyRateLimitingConfig as X, createRequestId as Y, createSqlPayments as Z, createStack as _, type Authorize as a, hostError as a0, isServiceErrorShape as a1, isStackOptions as a2, jsonResponse as a3, mapHostRouteError as a4, paymentsSchemaSql as a5, resolveClientIp as a6, startNotificationListener as a7, startNotificationWorker as a8, type AuthorizeAction as b, type AuthorizeContext as c, type AuthorizeResource as d, type CheckoutCreatedInput as e, type CreateHostDbOptions as f, type CreateHostOptions as g, type CreateHostRepositoryOptions as h, type CreateHttpHandlerOptions as i, type CreateStackOptions as j, type HostCheckoutPrice as k, HostError as l, HttpError as m, type HttpHandler as n, type NotificationWorker as o, OPENRECEIVE_RECONCILE_BATCH_SIZE as p, type PaymentRecord as q, type PaymentRepository as r, type PaymentSettlement as s, type PaymentSettlementHook as t, type RateLimit as u, type ReconciliationTransition as v, type ResolveCheckoutContext as w, type ResolveCheckoutHook as x, type ResolvedHostCheckout as y, type ServiceErrorShape as z };
738
+ export { hostError as $, type AttemptStatus as A, type SettlementEventHook as B, type CheckoutCreatedHook as C, type SettlementRecord as D, type SqlClient as E, type SqlDatabase as F, type SqlPaymentRepository as G, type Host as H, type IpRateLimitConfig as I, type SqlPaymentsOptions as J, type SqlQuery as K, type Stack as L, type StackStorage as M, type NotificationListener as N, OPENRECEIVE_RECONCILE_BATCH_SIZE as O, type PaymentInsert as P, type StackWallet as Q, type ReconcilableAttempt as R, type SqlAdapter as S, createHost as T, createHttpHandler as U, createIpRateLimit as V, createProxyRateLimitingConfig as W, createRequestId as X, createSqlPayments as Y, createStack as Z, errorResponse as _, type Authorize as a, isServiceErrorShape as a0, isStackOptions as a1, jsonResponse as a2, mapHostRouteError as a3, paymentsSchemaSql as a4, resolveClientIp as a5, startNotificationListener as a6, startNotificationWorker as a7, type AuthorizeAction as b, type AuthorizeContext as c, type AuthorizeResource as d, type CheckoutCreatedInput as e, type CreateHostDbOptions as f, type CreateHostOptions as g, type CreateHostRepositoryOptions as h, type CreateHttpHandlerOptions as i, type CreateStackOptions as j, type HostCheckoutPrice as k, HostError as l, HttpError as m, type HttpHandler as n, type NotificationWorker as o, type PaymentRecord as p, type PaymentRepository as q, type PaymentSettlement as r, type PaymentSettlementHook as s, type RateLimit as t, type ReconciliationTransition as u, type ResolveCheckoutContext as v, type ResolveCheckoutHook as w, type ResolvedHostCheckout as x, type ServiceErrorShape as y, type SettlementEvent as z };
@@ -1,3 +1,3 @@
1
1
  export { Checkout, CreateCheckoutAmount, OpenReceive, PaymentCheck, SwapCheckout } from '@openreceive/node';
2
- export { a as Authorize, b as AuthorizeAction, c as AuthorizeContext, d as AuthorizeResource, C as CheckoutCreatedHook, e as CheckoutCreatedInput, i as CreateHttpHandlerOptions, j as CreateStackOptions, H as Host, l as HostError, m as HttpError, n as HttpHandler, I as IpRateLimitConfig, o as NotificationWorker, r as PaymentRepository, s as PaymentSettlement, t as PaymentSettlementHook, u as RateLimit, w as ResolveCheckoutContext, x as ResolveCheckoutHook, y as ResolvedHostCheckout, z as ServiceErrorShape, B as SettlementEvent, D as SettlementEventHook, M as Stack, Q as StackStorage, T as StackWallet, V as createHttpHandler, _ as createStack, a0 as hostError, a1 as isServiceErrorShape, a4 as mapHostRouteError, a8 as startNotificationWorker } from './adapter-surface-DA8w4Sxj.js';
2
+ export { a as Authorize, b as AuthorizeAction, c as AuthorizeContext, d as AuthorizeResource, C as CheckoutCreatedHook, e as CheckoutCreatedInput, i as CreateHttpHandlerOptions, j as CreateStackOptions, H as Host, l as HostError, m as HttpError, n as HttpHandler, I as IpRateLimitConfig, o as NotificationWorker, q as PaymentRepository, r as PaymentSettlement, s as PaymentSettlementHook, t as RateLimit, v as ResolveCheckoutContext, w as ResolveCheckoutHook, x as ResolvedHostCheckout, y as ServiceErrorShape, z as SettlementEvent, B as SettlementEventHook, L as Stack, M as StackStorage, Q as StackWallet, U as createHttpHandler, Z as createStack, $ as hostError, a0 as isServiceErrorShape, a3 as mapHostRouteError, a7 as startNotificationWorker } from './adapter-surface-DHngkTKQ.js';
3
3
  import '@openreceive/core';
@@ -7,7 +7,7 @@ import {
7
7
  isServiceErrorShape,
8
8
  mapHostRouteError,
9
9
  startNotificationWorker
10
- } from "./chunk-YASZ4HDW.js";
10
+ } from "./chunk-TJY2HBVU.js";
11
11
  export {
12
12
  HostError,
13
13
  HttpError,
@@ -231,10 +231,10 @@ import { sanitizeEvent } from "@openreceive/node";
231
231
 
232
232
  // src/payment-repository.ts
233
233
  import {
234
+ OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS,
234
235
  unixSeconds
235
236
  } from "@openreceive/core";
236
237
  var OPENRECEIVE_ATTEMPT_REUSE_BUFFER_SECONDS = 60;
237
- var OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS = 900;
238
238
  function isReusablePaymentAttempt(expiresAt, now = unixSeconds()) {
239
239
  return expiresAt - now > OPENRECEIVE_ATTEMPT_REUSE_BUFFER_SECONDS;
240
240
  }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { OpenReceive, PaymentCheck } from '@openreceive/node';
2
2
  export { Checkout, CreateCheckoutAmount, OpenReceive, PaymentCheck, SwapCheckout } from '@openreceive/node';
3
- import { H as Host, R as ReconcilableAttempt, S as SqlAdapter } from './adapter-surface-DA8w4Sxj.js';
4
- export { A as AttemptStatus, a as Authorize, b as AuthorizeAction, c as AuthorizeContext, d as AuthorizeResource, C as CheckoutCreatedHook, e as CheckoutCreatedInput, f as CreateHostDbOptions, g as CreateHostOptions, h as CreateHostRepositoryOptions, i as CreateHttpHandlerOptions, j as CreateStackOptions, k as HostCheckoutPrice, l as HostError, m as HttpError, n as HttpHandler, I as IpRateLimitConfig, N as NotificationListener, o as NotificationWorker, O as OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS, p as OPENRECEIVE_RECONCILE_BATCH_SIZE, P as PaymentInsert, q as PaymentRecord, r as PaymentRepository, s as PaymentSettlement, t as PaymentSettlementHook, u as RateLimit, v as ReconciliationTransition, w as ResolveCheckoutContext, x as ResolveCheckoutHook, y as ResolvedHostCheckout, z as ServiceErrorShape, B as SettlementEvent, D as SettlementEventHook, E as SettlementRecord, F as SqlClient, G as SqlDatabase, J as SqlPaymentRepository, K as SqlPaymentsOptions, L as SqlQuery, M as Stack, Q as StackStorage, T as StackWallet, U as createHost, V as createHttpHandler, W as createIpRateLimit, X as createProxyRateLimitingConfig, Y as createRequestId, Z as createSqlPayments, _ as createStack, $ as errorResponse, a0 as hostError, a1 as isServiceErrorShape, a2 as isStackOptions, a3 as jsonResponse, a4 as mapHostRouteError, a5 as paymentsSchemaSql, a6 as resolveClientIp, a7 as startNotificationListener, a8 as startNotificationWorker } from './adapter-surface-DA8w4Sxj.js';
5
- export { OPENRECEIVE_PAYMENTS_SCHEMA_VERSION } from '@openreceive/core';
3
+ import { H as Host, R as ReconcilableAttempt, S as SqlAdapter } from './adapter-surface-DHngkTKQ.js';
4
+ export { A as AttemptStatus, a as Authorize, b as AuthorizeAction, c as AuthorizeContext, d as AuthorizeResource, C as CheckoutCreatedHook, e as CheckoutCreatedInput, f as CreateHostDbOptions, g as CreateHostOptions, h as CreateHostRepositoryOptions, i as CreateHttpHandlerOptions, j as CreateStackOptions, k as HostCheckoutPrice, l as HostError, m as HttpError, n as HttpHandler, I as IpRateLimitConfig, N as NotificationListener, o as NotificationWorker, O as OPENRECEIVE_RECONCILE_BATCH_SIZE, P as PaymentInsert, p as PaymentRecord, q as PaymentRepository, r as PaymentSettlement, s as PaymentSettlementHook, t as RateLimit, u as ReconciliationTransition, v as ResolveCheckoutContext, w as ResolveCheckoutHook, x as ResolvedHostCheckout, y as ServiceErrorShape, z as SettlementEvent, B as SettlementEventHook, D as SettlementRecord, E as SqlClient, F as SqlDatabase, G as SqlPaymentRepository, J as SqlPaymentsOptions, K as SqlQuery, L as Stack, M as StackStorage, Q as StackWallet, T as createHost, U as createHttpHandler, V as createIpRateLimit, W as createProxyRateLimitingConfig, X as createRequestId, Y as createSqlPayments, Z as createStack, _ as errorResponse, $ as hostError, a0 as isServiceErrorShape, a1 as isStackOptions, a2 as jsonResponse, a3 as mapHostRouteError, a4 as paymentsSchemaSql, a5 as resolveClientIp, a6 as startNotificationListener, a7 as startNotificationWorker } from './adapter-surface-DHngkTKQ.js';
5
+ export { OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS, OPENRECEIVE_PAYMENTS_SCHEMA_VERSION } from '@openreceive/core';
6
6
 
7
7
  /** The pieces of a framework request the bridge needs, framework-agnostic. */
8
8
  interface NodeRequestParts {
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  startReconciler,
35
35
  typeOrmDb,
36
36
  webRequest
37
- } from "./chunk-YASZ4HDW.js";
37
+ } from "./chunk-TJY2HBVU.js";
38
38
  export {
39
39
  HostError,
40
40
  HttpError,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openreceive/http",
3
- "version": "0.4.3",
4
- "description": "Framework-neutral (Web Request/Response) HTTP handler for OpenReceive checkout that builds on @openreceive/node and requires its Node runtime: request routing, host integration, and payment-attempt persistence.",
3
+ "version": "0.4.6",
4
+ "description": "Node.js HTTP routes and payment storage for Bitcoin Lightning checkout, with optional USDT, USDC, SOL and ETH swaps.",
5
5
  "keywords": [
6
6
  "bitcoin",
7
7
  "lightning",
@@ -17,8 +17,8 @@
17
17
  "main": "./dist/index.js",
18
18
  "types": "./dist/index.d.ts",
19
19
  "dependencies": {
20
- "@openreceive/core": "0.4.3",
21
- "@openreceive/node": "0.4.3"
20
+ "@openreceive/core": "0.4.6",
21
+ "@openreceive/node": "0.4.6"
22
22
  },
23
23
  "exports": {
24
24
  ".": {
@@ -5,7 +5,8 @@ description: >
5
5
  Use when adding Bitcoin, Lightning, or crypto checkout to a Node.js, Express,
6
6
  Fastify, Next.js, Rails, React, Vue, Svelte, Angular, or plain-HTML
7
7
  application with OpenReceive (the @openreceive/* npm packages or the
8
- openreceive-rails gem).
8
+ openreceive-rails gem), or when connecting a BTCPay Server store to a
9
+ receive-only NWC wallet with the OpenReceive plugin.
9
10
  license: MIT
10
11
  ---
11
12
 
@@ -23,15 +24,25 @@ code** (`NWC_URI`).
23
24
  1. Identify the server stack of the application you are in.
24
25
  2. Open the matching reference — it is complete (quickstart inlined) and needs
25
26
  no network access:
26
- - Node (Express / Fastify / Next.js): [references/node.md](references/node.md)
27
+ - Node, Express: [references/node.md](references/node.md)
28
+ - Node, Fastify: [references/fastify.md](references/fastify.md)
29
+ - Node, Next.js App Router: [references/next.md](references/next.md)
27
30
  - Rails: [references/rails.md](references/rails.md)
31
+ - Django: [references/django.md](references/django.md)
32
+ - Laravel: [references/laravel.md](references/laravel.md)
33
+ - WordPress + WooCommerce: [references/woocommerce.md](references/woocommerce.md) — the packaged gateway and merchant settings.
34
+ - BTCPay Server: [references/btcpay.md](references/btcpay.md) — a plugin,
35
+ configured in BTCPay's store UI or Greenfield API; no application code,
36
+ no npm packages, no gem. The rest of this file is about the library.
28
37
  3. Follow its **Step 0** first: confirm `NWC_URI` is set in the server
29
38
  environment before writing code. Never print the value; never invent a
30
39
  placeholder.
31
40
 
32
- Install (Node): `npm install @openreceive/express @openreceive/react` — swap
33
- the adapter (`fastify`, `next`) and UI package (`vue`, `svelte`, `angular`,
34
- `elements`) for the stack. Install (Rails): `bundle add openreceive-rails`.
41
+ Install, per adapter — Express: `npm install @openreceive/express @openreceive/react`;
42
+ Fastify: `npm install @openreceive/fastify @openreceive/react`; Next.js:
43
+ `npm install @openreceive/next @openreceive/react`. Swap the UI package (`vue`,
44
+ `svelte`, `angular`, `elements`) for the frontend the app already has. Install
45
+ (Rails): `bundle add openreceive-rails`.
35
46
 
36
47
  ## The three server objects
37
48
 
@@ -0,0 +1,193 @@
1
+ # OpenReceive agent directions (BTCPay Server)
2
+
3
+ These directions describe OpenReceive 0.4.6.
4
+
5
+ Connect a BTCPay Server store to a receive-only NWC wallet with the OpenReceive
6
+ plugin, and optionally let payers pay BTCPay invoices with USDT, USDC, ETH or
7
+ SOL. You do not need a copy of the OpenReceive source, and there is no
8
+ application code to write: the plugin is configured through BTCPay's store UI
9
+ or its Greenfield API, and the quickstart is appended to this file in full.
10
+
11
+ This is the BTCPay plugin, not the Node or Rails library. Do not install
12
+ `@openreceive/*` packages or the `openreceive-rails` gem into a BTCPay
13
+ deployment, do not add `openreceive_payments` tables, and do not mount
14
+ OpenReceive HTTP routes. BTCPay's invoices, checkout, webhooks and Greenfield
15
+ API are the host; the plugin only supplies the Lightning backend and the swap
16
+ rail.
17
+
18
+ ## What the plugin is
19
+
20
+ A BTCPay Server plugin (`BTCPayServer.Plugins.OpenReceive`) that registers a
21
+ Lightning connection-string handler for `type=openreceive;nwc=<NWC URI>`.
22
+ Saving that string makes the NWC wallet the store's Lightning node: BTCPay
23
+ mints every Lightning invoice in that wallet and its own `LightningListener`
24
+ records the payments. The plugin never calls a NIP-47 `pay_*` method, so
25
+ every send-side BTCPay feature (Lightning payouts, pull-payment refunds over
26
+ Lightning, the send tab) is unavailable by design.
27
+
28
+ The one required credential is a receive-only NWC code. A Lightning Swap
29
+ Connect (LSC) code optionally adds server-side swaps: a provider order aimed at
30
+ the invoice's existing BOLT11, tracked in the plugin's own table, with the
31
+ refund path on the same checkout screen.
32
+
33
+ ## Step 0 — check the deployment before you change anything
34
+
35
+ 1. Confirm the BTCPay Server version is 2.4.2 or later (Server Settings →
36
+ About, or `GET /api/v1/server/info`). The plugin declares that minimum and
37
+ BTCPay refuses to load it below.
38
+ 2. Check whether the plugin is installed (Server Settings → Plugins, or the
39
+ store navigation shows an "OpenReceive" entry). If not, install it from the
40
+ BTCPay plugin directory (Server Settings → Plugins, search "OpenReceive"),
41
+ as the quickstart says; do not invent an installer command.
42
+ 3. Check whether the store already has an OpenReceive connection:
43
+ `GET /api/v1/stores/{storeId}/openreceive/settings` returns
44
+ `lightningNodeIsOpenReceive`. If true, the wallet step is done — go to
45
+ swaps only if the user wants them.
46
+ 4. If no receive-only NWC code is available, stop and tell the user exactly
47
+ what to create:
48
+
49
+ > OpenReceive cannot mint an invoice without a receive-only NWC code. Get
50
+ > one at https://openreceive.org/get_a_nwc_code_to_receive_payments and
51
+ > paste it into Store → OpenReceive → Test connection, or hand it to me and
52
+ > I will set it through the Greenfield API.
53
+
54
+ Never print, log or echo the code; report only whether it is set. Never
55
+ paste a bare `nostr+walletconnect://` string into BTCPay's Lightning node
56
+ screen — that form is claimed by the Nostr plugin, without the receive-only
57
+ guard.
58
+ 5. If the user wants altcoin payments, ask for an LSC code from
59
+ https://openreceive.org/set_up_swap_provider. Do not wait for it: the
60
+ wallet works without it, and swaps switch on later with one settings change.
61
+
62
+ Only then start the quickstart.
63
+
64
+ ## Non-negotiables
65
+
66
+ - The connection string is `type=openreceive;nwc=<NWC URI>[;allow-spend=true]`
67
+ and nothing else. Set it through the setup page or
68
+ `PUT /api/v1/stores/{storeId}/openreceive/settings` with `nwcUri`, never by
69
+ editing BTCPay's Lightning node screen by hand.
70
+ - Receive-only is required. A code that advertises `pay_invoice` or another
71
+ spend method is refused on save. The override (`allowSpendCapableWallet`,
72
+ the checkbox on the setup page) is the user's explicit choice; never tick it
73
+ to make a save succeed.
74
+ - The wallet's network must match BTCPay's. A mismatch is a refusal, not a
75
+ warning.
76
+ - The wallet must grant `make_invoice` and `list_transactions`.
77
+ `lookup_invoice` is optional; do not ask the user for a code that grants it.
78
+ - Swaps require the store's Lightning node to be the OpenReceive connection.
79
+ Enabling swaps on a store using the internal node is refused
80
+ (`wallet_required`).
81
+ - Swaps set the store's invoice expiration to 60 minutes when it is shorter,
82
+ and the plugin refuses to create a swap on an invoice with less than the
83
+ provider's window left. Do not lower the expiration below 45 minutes on a
84
+ swap-enabled store.
85
+ - Top-up (amountless) invoices are unsupported on this backend. Do not
86
+ configure a point of sale or payment link that relies on them with this
87
+ wallet.
88
+ - Secrets stay server-side. The NWC code and LSC code live in BTCPay's
89
+ database like every other BTCPay credential; never copy them into
90
+ screenshots, tickets, browser code or logs. The provider's order token never
91
+ leaves the server.
92
+ - BTCPay's `LightningListener` is the settlement authority. Provider
93
+ `completed` is not payment; only the wallet reporting the Lightning invoice
94
+ settled is. Do not build anything that fulfils on a provider state.
95
+ - There is no merchant-initiated refund of a settled Lightning payment. A swap
96
+ refund is a payer reclaiming a deposit that never converted, and only from
97
+ the `refund_required` provider state.
98
+
99
+ ## Verifying
100
+
101
+ Store → OpenReceive → **Run a health check** (the doctor page) runs every probe now: connection, preflight,
102
+ notifications, last scan, provider reachability, invoice expiration, swaps
103
+ needing attention. On a regtest machine, `packages/dotnet/docker/up.sh` then
104
+ `e2e.sh` in the OpenReceive repository proves the whole path end to end, and
105
+ that is the only situation where cloning the repository is the right move.
106
+
107
+ ## More documentation
108
+
109
+ Fetch one when the moment comes. Each is raw markdown, so a plain GET is
110
+ enough; drop the `.md` for the same page a person would read.
111
+
112
+ - https://openreceive.org/guides/btcpay-reference.md — every setting, route, swap state, doctor probe and log event of the plugin
113
+ - https://openreceive.org/guides/security.md — why receive-only is the only wallet credential
114
+ - https://openreceive.org/guides/lightning-swap-connect.md — what an LSC code actually is
115
+ - https://openreceive.org/guides/automated-swaps.md — provider states, and what turning swaps on commits a merchant to
116
+ - https://openreceive.org/guides/swap-refunds.md — the refund states; the route back is BTCPay's own invoice checkout page here
117
+ - https://openreceive.org/guides.md — the index, if what you need is not above
118
+
119
+ Questions, or a problem with the plugin itself:
120
+ https://openreceive.org/contact
121
+
122
+ ---
123
+
124
+ ## The quickstart, in full
125
+
126
+ Inlined verbatim so this file needs no network access — follow it once Step 0
127
+ passes. The page it comes from is https://openreceive.org/guides/quickstart-btcpay.
128
+
129
+ ## BTCPay Server quickstart
130
+
131
+ Requires BTCPay Server ≥ 2.4.2.
132
+
133
+ The OpenReceive plugin makes a receive-only NWC wallet the Lightning node of a
134
+ BTCPay store. BTCPay mints every Lightning invoice in that wallet and records
135
+ payments through its own settlement machinery. Optionally, payers can pay a
136
+ BTCPay invoice with USDT, USDC, ETH or SOL through a Lightning Swap Connect
137
+ provider; the swap settles into the same wallet. The store's internal node is
138
+ never used.
139
+
140
+ This is not the Node or Rails library. There are no hooks, no
141
+ `openreceive_payments` table and no OpenReceive HTTP routes: BTCPay's
142
+ invoices, checkout, webhooks and Greenfield API are the host.
143
+
144
+ ### 1. Prerequisites
145
+
146
+ - A BTCPay Server, version 2.4.2 or later, on any network (mainnet, testnet,
147
+ signet, regtest). The wallet must be on the same network.
148
+ - A receive-only NWC code for the wallet you want to receive into
149
+ ([get one here](https://openreceive.org/get_a_nwc_code_to_receive_payments)).
150
+ The code must grant `make_invoice` and `list_transactions` and must not
151
+ advertise any spend method. `lookup_invoice` is optional.
152
+ - Optionally, a Lightning Swap Connect (LSC) code from a
153
+ [swap provider](https://openreceive.org/set_up_swap_provider), if payers
154
+ should be able to pay with USDT, USDC, ETH or SOL.
155
+
156
+ ### 2. Install the plugin
157
+
158
+ In BTCPay, open **Server Settings → Plugins**, search the plugin directory
159
+ for **OpenReceive**, click **Install**, and restart BTCPay when prompted.
160
+ BTCPay creates the plugin's one table (`openreceive_swaps`, schema
161
+ `BTCPayServer.Plugins.OpenReceive`) in its own Postgres at startup; nothing
162
+ else is created.
163
+
164
+ To build the plugin from source instead, follow
165
+ [the .NET workspace README](https://github.com/OpenReceive/openreceive/blob/master/packages/dotnet/README.md).
166
+
167
+ ### 3. Connect the wallet
168
+
169
+ Follow the plugin README's illustrated walkthrough:
170
+ [OpenReceive for BTCPay Server](https://github.com/OpenReceive/openreceive/blob/master/packages/dotnet/BTCPayServer.Plugins.OpenReceive/README.md).
171
+ It opens the **OpenReceive** page in the store's sidebar, saves the
172
+ receive-only NWC code, optionally saves the LSC code to turn swaps on, and
173
+ creates a first test invoice. There is nothing else to configure: you never
174
+ open BTCPay's Lightning node screen, and the plugin never reads the internal
175
+ node.
176
+
177
+ Saving fails closed if the wallet advertises a spend method such as
178
+ `pay_invoice`. Mint a receive-only code instead; the override for a wallet
179
+ that cannot is a deliberate, logged choice. Swaps raise the store's invoice
180
+ expiration to 60 minutes when it is shorter, because a swap needs at least 45
181
+ minutes of invoice life.
182
+
183
+ ### 4. Check it
184
+
185
+ **Run a health check** on the OpenReceive page runs every probe in place:
186
+ the connection, the wallet preflight, payment notifications, the last wallet
187
+ scan, the swap provider and its assets, the invoice expiration, and swaps
188
+ that need a human. Each failing probe carries a fix link.
189
+
190
+ Every setting, Greenfield route, swap state, log event and probe is in the
191
+ [BTCPay plugin reference](https://openreceive.org/guides/btcpay-reference.md), including what is
192
+ unsupported by design: every send-side feature, top-up invoices, and a bare
193
+ `nostr+walletconnect://` string in BTCPay's Lightning node screen.