@happyvertical/payments 0.92.0 → 0.93.0
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 +47 -0
- package/dist/adapters/btcpay-client.d.ts +175 -0
- package/dist/adapters/btcpay-client.d.ts.map +1 -0
- package/dist/adapters/btcpay-gateway.d.ts +26 -0
- package/dist/adapters/btcpay-gateway.d.ts.map +1 -0
- package/dist/adapters/btcpay.d.ts +4 -167
- package/dist/adapters/btcpay.d.ts.map +1 -1
- package/dist/adapters/btcpay.js +310 -5
- package/dist/adapters/btcpay.js.map +1 -1
- package/dist/checkout-gateway.d.ts +119 -0
- package/dist/checkout-gateway.d.ts.map +1 -0
- package/dist/chunks/checkout-gateway-DG-LY0oG.js +42 -0
- package/dist/chunks/checkout-gateway-DG-LY0oG.js.map +1 -0
- package/dist/chunks/errors-feZrwnTy.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,6 +95,53 @@ never `retryable`: look it up by `orderId` before creating another. Messages nev
|
|
|
95
95
|
API key needs only `btcpay.store.canviewinvoices` and
|
|
96
96
|
`btcpay.store.cancreateinvoice` for these calls.
|
|
97
97
|
|
|
98
|
+
### Crypto checkout gateway (provider-neutral)
|
|
99
|
+
|
|
100
|
+
`CryptoCheckoutGateway` (root export) is the narrow port billing
|
|
101
|
+
code uses for **hosted crypto checkouts priced in fiat**. BTCPay is one
|
|
102
|
+
implementation (`createBtcpayCheckoutGateway` from
|
|
103
|
+
`@happyvertical/payments/btcpay`); a dedicated crypto-payments service can
|
|
104
|
+
implement the same port later without changing callers.
|
|
105
|
+
|
|
106
|
+
- `createCheckout({ orderId, amount, currency, metadata, redirectUrl })` —
|
|
107
|
+
`amount` is integer fiat minor units. Idempotent by `orderId`: a live
|
|
108
|
+
checkout is returned (a different price for the same order is refused); an
|
|
109
|
+
expired or invalid one is never revived.
|
|
110
|
+
- `getCheckout(id)` / `listCheckouts({ orderId })` return `status`
|
|
111
|
+
(`open` → `confirming` → `settled`, or `expired` / `invalid`), an
|
|
112
|
+
`exception` (`underpaid`, `overpaid`, `paid_late`, `manually_marked`), the
|
|
113
|
+
locked fiat `amount`, `amountPaid` (fiat minor units, rounded down), native
|
|
114
|
+
amounts, rate, rate source, and each payment (asset, rail, amount, fee,
|
|
115
|
+
status, txid).
|
|
116
|
+
- `verifyWebhook(rawBody, headers)` authenticates a delivery and returns ids
|
|
117
|
+
only (`eventId` is stable across redeliveries). Always act on
|
|
118
|
+
`getCheckout()`, never on the webhook body. `getCheckout()` throws
|
|
119
|
+
`CryptoCheckoutNotOwnedError` for a checkout the gateway did not create (for
|
|
120
|
+
example an invoice made by hand at the provider): acknowledge and ignore it.
|
|
121
|
+
- Returned `metadata` holds only the caller's own keys, so it round-trips
|
|
122
|
+
into `createCheckout`.
|
|
123
|
+
|
|
124
|
+
**Settlement belongs to the gateway.** `settled` means the gateway's own
|
|
125
|
+
confirmation policy is met; callers never count confirmations. For BTCPay that
|
|
126
|
+
policy is the required `speedPolicy` option (`HighSpeed` 0, `MediumSpeed` 1,
|
|
127
|
+
`LowMediumSpeed` 2, `LowSpeed` 6 confirmations — the only values BTCPay
|
|
128
|
+
supports). Lightning needs no caller change: add `BTC-LN` to `paymentMethods`
|
|
129
|
+
and payments arrive with `rail: 'lightning'`.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { BtcpayClient, createBtcpayCheckoutGateway } from '@happyvertical/payments/btcpay';
|
|
133
|
+
|
|
134
|
+
const gateway = createBtcpayCheckoutGateway({
|
|
135
|
+
client: new BtcpayClient({ baseUrl, apiKey, storeId }),
|
|
136
|
+
webhookSecret,
|
|
137
|
+
speedPolicy: 'LowSpeed',
|
|
138
|
+
paymentMethods: ['BTC-CHAIN'],
|
|
139
|
+
expirationMinutes: 15,
|
|
140
|
+
paymentTolerance: 0,
|
|
141
|
+
rateSource: 'kraken',
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
98
145
|
### Save a card (setup) → charge later
|
|
99
146
|
|
|
100
147
|
```ts
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { PaymentProviderError } from '../errors.js';
|
|
2
|
+
import { FetchLike } from '../shared.js';
|
|
3
|
+
/** Invoice status as reported by Greenfield. */
|
|
4
|
+
export type BtcpayInvoiceStatus = 'New' | 'Processing' | 'Expired' | 'Invalid' | 'Settled';
|
|
5
|
+
/** Greenfield's `additionalStatus` qualifier on an invoice. */
|
|
6
|
+
export type BtcpayInvoiceAdditionalStatus = 'None' | 'PaidLate' | 'PaidPartial' | 'Marked' | 'Invalid' | 'PaidOver';
|
|
7
|
+
/**
|
|
8
|
+
* Confirmations before BTCPay settles an on-chain payment: `HighSpeed` 0
|
|
9
|
+
* (1 for RBF-signalling transactions), `MediumSpeed` 1, `LowMediumSpeed` 2,
|
|
10
|
+
* `LowSpeed` 6. These are the only values BTCPay supports.
|
|
11
|
+
*/
|
|
12
|
+
export type BtcpaySpeedPolicy = 'HighSpeed' | 'MediumSpeed' | 'LowMediumSpeed' | 'LowSpeed';
|
|
13
|
+
export interface BtcpayInvoiceCheckoutOptions {
|
|
14
|
+
speedPolicy?: BtcpaySpeedPolicy;
|
|
15
|
+
/** Payment method ids, for example `['BTC-CHAIN']` or `['BTC-CHAIN', 'BTC-LN']`. */
|
|
16
|
+
paymentMethods?: string[];
|
|
17
|
+
defaultPaymentMethod?: string;
|
|
18
|
+
/** Minutes the rate is locked and the invoice accepts new payments. */
|
|
19
|
+
expirationMinutes?: number;
|
|
20
|
+
/** Minutes after expiry during which late payments are still tracked. */
|
|
21
|
+
monitoringMinutes?: number;
|
|
22
|
+
/** Percentage underpayment BTCPay treats as paid (0–100). */
|
|
23
|
+
paymentTolerance?: number;
|
|
24
|
+
redirectURL?: string;
|
|
25
|
+
redirectAutomatically?: boolean;
|
|
26
|
+
defaultLanguage?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface BtcpayCreateInvoiceInput {
|
|
29
|
+
/** Decimal amount in `currency`, for example `'25.00'`. */
|
|
30
|
+
amount: string;
|
|
31
|
+
currency: string;
|
|
32
|
+
/** Merchant order id; stored as `metadata.orderId` and filterable. */
|
|
33
|
+
orderId?: string;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
checkout?: BtcpayInvoiceCheckoutOptions;
|
|
36
|
+
additionalSearchTerms?: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface BtcpayInvoice {
|
|
39
|
+
id: string;
|
|
40
|
+
storeId?: string;
|
|
41
|
+
status: BtcpayInvoiceStatus | string;
|
|
42
|
+
additionalStatus: BtcpayInvoiceAdditionalStatus | string;
|
|
43
|
+
/** Decimal amount in `currency`. */
|
|
44
|
+
amount: string;
|
|
45
|
+
currency: string;
|
|
46
|
+
checkoutLink?: string;
|
|
47
|
+
createdTime?: Date;
|
|
48
|
+
expirationTime?: Date;
|
|
49
|
+
monitoringExpiration?: Date;
|
|
50
|
+
archived: boolean;
|
|
51
|
+
metadata: Record<string, unknown>;
|
|
52
|
+
checkout: Record<string, unknown>;
|
|
53
|
+
raw: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
export interface BtcpayListInvoicesInput {
|
|
56
|
+
orderId?: string | string[];
|
|
57
|
+
status?: BtcpayInvoiceStatus | BtcpayInvoiceStatus[];
|
|
58
|
+
textSearch?: string;
|
|
59
|
+
/** Include archived invoices (Greenfield omits them by default). */
|
|
60
|
+
includeArchived?: boolean;
|
|
61
|
+
skip?: number;
|
|
62
|
+
take?: number;
|
|
63
|
+
}
|
|
64
|
+
export interface BtcpayInvoicePayment {
|
|
65
|
+
/** On-chain payments use `<txid>-<vout>`. */
|
|
66
|
+
id: string;
|
|
67
|
+
/** The transaction id of an on-chain payment (parsed from `id`). */
|
|
68
|
+
transactionId?: string;
|
|
69
|
+
receivedDate?: Date;
|
|
70
|
+
/** Decimal amount in the payment method's currency (BTC). */
|
|
71
|
+
value: string;
|
|
72
|
+
/** Decimal network/payment-method fee. */
|
|
73
|
+
fee: string;
|
|
74
|
+
status: 'Invalid' | 'Processing' | 'Settled' | string;
|
|
75
|
+
destination?: string;
|
|
76
|
+
}
|
|
77
|
+
export interface BtcpayInvoicePaymentMethod {
|
|
78
|
+
/** `BTC-CHAIN`, `BTC-LN`, … (Greenfield 2.x `paymentMethodId`). */
|
|
79
|
+
paymentMethodId: string;
|
|
80
|
+
/** The payment method's currency, for example `BTC`. */
|
|
81
|
+
currency?: string;
|
|
82
|
+
destination?: string;
|
|
83
|
+
paymentLink?: string;
|
|
84
|
+
/** Invoice-currency price of one unit of the payment currency, if reported. */
|
|
85
|
+
rate?: string;
|
|
86
|
+
/** Decimal amount due in the payment currency when created. */
|
|
87
|
+
amount: string;
|
|
88
|
+
/**
|
|
89
|
+
* Decimal amount paid through this method (Greenfield 1.x: `paid`).
|
|
90
|
+
* Undefined when BTCPay did not report it — never read absence as zero.
|
|
91
|
+
*/
|
|
92
|
+
paymentMethodPaid?: string;
|
|
93
|
+
/** Decimal amount paid through all methods, in this method's currency. */
|
|
94
|
+
totalPaid: string;
|
|
95
|
+
/**
|
|
96
|
+
* Decimal amount still due, in this method's currency. Undefined when
|
|
97
|
+
* BTCPay did not report it — never read a missing value as "nothing due".
|
|
98
|
+
*/
|
|
99
|
+
due?: string;
|
|
100
|
+
payments: BtcpayInvoicePayment[];
|
|
101
|
+
raw: Record<string, unknown>;
|
|
102
|
+
}
|
|
103
|
+
export interface BtcpayClientOptions {
|
|
104
|
+
/** Server origin, for example `https://btcpay.example.com` (no path). */
|
|
105
|
+
baseUrl: string;
|
|
106
|
+
/** Greenfield API key (`Authorization: token …`). */
|
|
107
|
+
apiKey: string;
|
|
108
|
+
storeId: string;
|
|
109
|
+
fetch?: FetchLike;
|
|
110
|
+
/** Per-request timeout (default 30 seconds). */
|
|
111
|
+
timeoutMs?: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A Greenfield request failed. Never carries the API key.
|
|
115
|
+
*
|
|
116
|
+
* `retryable` is true only when repeating the same call cannot duplicate a
|
|
117
|
+
* side effect: a read (`GET`) that failed on the network, with 429, or with
|
|
118
|
+
* 5xx, or any request refused with 429. A `createInvoice` that failed on the
|
|
119
|
+
* network or with 5xx may still have created the invoice, so it is not
|
|
120
|
+
* retryable: resolve it with `listInvoices({ orderId })` instead.
|
|
121
|
+
*/
|
|
122
|
+
export declare class BtcpayApiError extends PaymentProviderError {
|
|
123
|
+
readonly status: number;
|
|
124
|
+
readonly apiCode?: string;
|
|
125
|
+
constructor(message: string, status: number, apiCode?: string, options?: {
|
|
126
|
+
cause?: unknown;
|
|
127
|
+
method?: 'GET' | 'POST';
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
export declare class BtcpayClient {
|
|
131
|
+
readonly baseUrl: string;
|
|
132
|
+
readonly storeId: string;
|
|
133
|
+
private readonly apiKey;
|
|
134
|
+
private readonly fetch;
|
|
135
|
+
private readonly timeoutMs;
|
|
136
|
+
constructor(options: BtcpayClientOptions);
|
|
137
|
+
/**
|
|
138
|
+
* `POST /api/v1/stores/{storeId}/invoices`. Not idempotent at BTCPay: after
|
|
139
|
+
* a network or 5xx failure the invoice may exist, so the error is not
|
|
140
|
+
* `retryable` — look it up with `listInvoices({ orderId })` before creating
|
|
141
|
+
* another.
|
|
142
|
+
*/
|
|
143
|
+
createInvoice(input: BtcpayCreateInvoiceInput): Promise<BtcpayInvoice>;
|
|
144
|
+
/** `GET /api/v1/stores/{storeId}/invoices/{invoiceId}`. */
|
|
145
|
+
getInvoice(invoiceId: string): Promise<BtcpayInvoice>;
|
|
146
|
+
/** `GET /api/v1/stores/{storeId}/invoices` with Greenfield filters. */
|
|
147
|
+
listInvoices(input?: BtcpayListInvoicesInput): Promise<BtcpayInvoice[]>;
|
|
148
|
+
/** `GET /api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods`. */
|
|
149
|
+
getInvoicePaymentMethods(invoiceId: string): Promise<BtcpayInvoicePaymentMethod[]>;
|
|
150
|
+
private storePath;
|
|
151
|
+
private request;
|
|
152
|
+
}
|
|
153
|
+
/** A parsed BTCPay webhook delivery (signature must be verified first). */
|
|
154
|
+
export interface BtcpayWebhookDelivery {
|
|
155
|
+
deliveryId: string;
|
|
156
|
+
webhookId?: string;
|
|
157
|
+
/** Set on a redelivery: the id of the delivery it repeats. */
|
|
158
|
+
originalDeliveryId?: string;
|
|
159
|
+
isRedelivery: boolean;
|
|
160
|
+
/** `InvoiceSettled`, `InvoiceExpired`, … */
|
|
161
|
+
type: string;
|
|
162
|
+
timestamp?: Date;
|
|
163
|
+
storeId?: string;
|
|
164
|
+
invoiceId?: string;
|
|
165
|
+
metadata?: Record<string, unknown>;
|
|
166
|
+
raw: Record<string, unknown>;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Check a `BTCPay-Sig` header (`sha256=<hex>`) against the raw request body
|
|
170
|
+
* in constant time. Returns false for any missing or malformed input.
|
|
171
|
+
*/
|
|
172
|
+
export declare function isValidBtcpayWebhookSignature(rawBody: string, header: string | null | undefined, secret: string): boolean;
|
|
173
|
+
/** Parse a webhook body. Throws `PaymentProviderError` when it is malformed. */
|
|
174
|
+
export declare function parseBtcpayWebhook(rawBody: string): BtcpayWebhookDelivery;
|
|
175
|
+
//# sourceMappingURL=btcpay-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btcpay-client.d.ts","sourceRoot":"","sources":["../../src/adapters/btcpay-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CryptoCheckoutGateway } from '../checkout-gateway.js';
|
|
2
|
+
import { BtcpayClient, BtcpaySpeedPolicy } from './btcpay-client.js';
|
|
3
|
+
export declare const BTCPAY_GATEWAY_ID = "btcpay";
|
|
4
|
+
export interface BtcpayCheckoutGatewayOptions {
|
|
5
|
+
client: BtcpayClient;
|
|
6
|
+
/** The store webhook's secret (`BTCPay-Sig` HMAC key). */
|
|
7
|
+
webhookSecret: string;
|
|
8
|
+
/**
|
|
9
|
+
* Confirmations before BTCPay settles an on-chain payment: `HighSpeed` 0,
|
|
10
|
+
* `MediumSpeed` 1, `LowMediumSpeed` 2, `LowSpeed` 6. Required: settlement
|
|
11
|
+
* policy is an explicit decision, not a store default.
|
|
12
|
+
*/
|
|
13
|
+
speedPolicy: BtcpaySpeedPolicy;
|
|
14
|
+
/** BTCPay payment method ids (default `['BTC-CHAIN']`; add `BTC-LN` for Lightning). */
|
|
15
|
+
paymentMethods?: string[];
|
|
16
|
+
/** Rate lock in minutes (default 15). */
|
|
17
|
+
expirationMinutes?: number;
|
|
18
|
+
/** Minutes after expiry BTCPay still tracks late payments (default 1440). */
|
|
19
|
+
monitoringMinutes?: number;
|
|
20
|
+
/** Underpayment percentage BTCPay treats as paid (default 0). */
|
|
21
|
+
paymentTolerance?: number;
|
|
22
|
+
/** A label for the store's rate source, recorded on every checkout. */
|
|
23
|
+
rateSource?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function createBtcpayCheckoutGateway(options: BtcpayCheckoutGatewayOptions): CryptoCheckoutGateway;
|
|
26
|
+
//# sourceMappingURL=btcpay-gateway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btcpay-gateway.d.ts","sourceRoot":"","sources":["../../src/adapters/btcpay-gateway.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAKL,KAAK,qBAAqB,EAI3B,MAAM,wBAAwB,CAAC;AAOhC,OAAO,EACL,KAAK,YAAY,EAGjB,KAAK,iBAAiB,EAGvB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,YAAY,CAAC;IACrB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,WAAW,EAAE,iBAAiB,CAAC;IAC/B,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,yCAAyC;IACzC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA2CD,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B,GACpC,qBAAqB,CAqMvB"}
|
|
@@ -1,170 +1,7 @@
|
|
|
1
|
-
import { PaymentProviderError } from '../errors.js';
|
|
2
|
-
import { FetchLike } from '../shared.js';
|
|
3
|
-
/** Invoice status as reported by Greenfield. */
|
|
4
|
-
export type BtcpayInvoiceStatus = 'New' | 'Processing' | 'Expired' | 'Invalid' | 'Settled';
|
|
5
|
-
/** Greenfield's `additionalStatus` qualifier on an invoice. */
|
|
6
|
-
export type BtcpayInvoiceAdditionalStatus = 'None' | 'PaidLate' | 'PaidPartial' | 'Marked' | 'Invalid' | 'PaidOver';
|
|
7
1
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `LowSpeed` 6. These are the only values BTCPay supports.
|
|
2
|
+
* `@happyvertical/payments/btcpay`: the BTCPay Server Greenfield client and
|
|
3
|
+
* the BTCPay implementation of {@link CryptoCheckoutGateway}.
|
|
11
4
|
*/
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
speedPolicy?: BtcpaySpeedPolicy;
|
|
15
|
-
/** Payment method ids, for example `['BTC-CHAIN']` or `['BTC-CHAIN', 'BTC-LN']`. */
|
|
16
|
-
paymentMethods?: string[];
|
|
17
|
-
defaultPaymentMethod?: string;
|
|
18
|
-
/** Minutes the rate is locked and the invoice accepts new payments. */
|
|
19
|
-
expirationMinutes?: number;
|
|
20
|
-
/** Minutes after expiry during which late payments are still tracked. */
|
|
21
|
-
monitoringMinutes?: number;
|
|
22
|
-
/** Percentage underpayment BTCPay treats as paid (0–100). */
|
|
23
|
-
paymentTolerance?: number;
|
|
24
|
-
redirectURL?: string;
|
|
25
|
-
redirectAutomatically?: boolean;
|
|
26
|
-
defaultLanguage?: string;
|
|
27
|
-
}
|
|
28
|
-
export interface BtcpayCreateInvoiceInput {
|
|
29
|
-
/** Decimal amount in `currency`, for example `'25.00'`. */
|
|
30
|
-
amount: string;
|
|
31
|
-
currency: string;
|
|
32
|
-
/** Merchant order id; stored as `metadata.orderId` and filterable. */
|
|
33
|
-
orderId?: string;
|
|
34
|
-
metadata?: Record<string, unknown>;
|
|
35
|
-
checkout?: BtcpayInvoiceCheckoutOptions;
|
|
36
|
-
additionalSearchTerms?: string[];
|
|
37
|
-
}
|
|
38
|
-
export interface BtcpayInvoice {
|
|
39
|
-
id: string;
|
|
40
|
-
storeId?: string;
|
|
41
|
-
status: BtcpayInvoiceStatus | string;
|
|
42
|
-
additionalStatus: BtcpayInvoiceAdditionalStatus | string;
|
|
43
|
-
/** Decimal amount in `currency`. */
|
|
44
|
-
amount: string;
|
|
45
|
-
currency: string;
|
|
46
|
-
checkoutLink?: string;
|
|
47
|
-
createdTime?: Date;
|
|
48
|
-
expirationTime?: Date;
|
|
49
|
-
monitoringExpiration?: Date;
|
|
50
|
-
archived: boolean;
|
|
51
|
-
metadata: Record<string, unknown>;
|
|
52
|
-
checkout: Record<string, unknown>;
|
|
53
|
-
raw: Record<string, unknown>;
|
|
54
|
-
}
|
|
55
|
-
export interface BtcpayListInvoicesInput {
|
|
56
|
-
orderId?: string | string[];
|
|
57
|
-
status?: BtcpayInvoiceStatus | BtcpayInvoiceStatus[];
|
|
58
|
-
textSearch?: string;
|
|
59
|
-
skip?: number;
|
|
60
|
-
take?: number;
|
|
61
|
-
}
|
|
62
|
-
export interface BtcpayInvoicePayment {
|
|
63
|
-
/** On-chain payments use `<txid>-<vout>`. */
|
|
64
|
-
id: string;
|
|
65
|
-
/** The transaction id of an on-chain payment (parsed from `id`). */
|
|
66
|
-
transactionId?: string;
|
|
67
|
-
receivedDate?: Date;
|
|
68
|
-
/** Decimal amount in the payment method's currency (BTC). */
|
|
69
|
-
value: string;
|
|
70
|
-
/** Decimal network/payment-method fee. */
|
|
71
|
-
fee: string;
|
|
72
|
-
status: 'Invalid' | 'Processing' | 'Settled' | string;
|
|
73
|
-
destination?: string;
|
|
74
|
-
}
|
|
75
|
-
export interface BtcpayInvoicePaymentMethod {
|
|
76
|
-
/** `BTC-CHAIN`, `BTC-LN`, … (Greenfield 2.x `paymentMethodId`). */
|
|
77
|
-
paymentMethodId: string;
|
|
78
|
-
/** The payment method's currency, for example `BTC`. */
|
|
79
|
-
currency?: string;
|
|
80
|
-
destination?: string;
|
|
81
|
-
paymentLink?: string;
|
|
82
|
-
/** Invoice-currency price of one unit of the payment currency, if reported. */
|
|
83
|
-
rate?: string;
|
|
84
|
-
/** Decimal amount due in the payment currency when created. */
|
|
85
|
-
amount: string;
|
|
86
|
-
/** Decimal amount paid through this method. */
|
|
87
|
-
paymentMethodPaid: string;
|
|
88
|
-
/** Decimal amount paid through all methods, in this method's currency. */
|
|
89
|
-
totalPaid: string;
|
|
90
|
-
/**
|
|
91
|
-
* Decimal amount still due, in this method's currency. Undefined when
|
|
92
|
-
* BTCPay did not report it — never read a missing value as "nothing due".
|
|
93
|
-
*/
|
|
94
|
-
due?: string;
|
|
95
|
-
payments: BtcpayInvoicePayment[];
|
|
96
|
-
raw: Record<string, unknown>;
|
|
97
|
-
}
|
|
98
|
-
export interface BtcpayClientOptions {
|
|
99
|
-
/** Server origin, for example `https://btcpay.example.com` (no path). */
|
|
100
|
-
baseUrl: string;
|
|
101
|
-
/** Greenfield API key (`Authorization: token …`). */
|
|
102
|
-
apiKey: string;
|
|
103
|
-
storeId: string;
|
|
104
|
-
fetch?: FetchLike;
|
|
105
|
-
/** Per-request timeout (default 30 seconds). */
|
|
106
|
-
timeoutMs?: number;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* A Greenfield request failed. Never carries the API key.
|
|
110
|
-
*
|
|
111
|
-
* `retryable` is true only when repeating the same call cannot duplicate a
|
|
112
|
-
* side effect: a read (`GET`) that failed on the network, with 429, or with
|
|
113
|
-
* 5xx, or any request refused with 429. A `createInvoice` that failed on the
|
|
114
|
-
* network or with 5xx may still have created the invoice, so it is not
|
|
115
|
-
* retryable: resolve it with `listInvoices({ orderId })` instead.
|
|
116
|
-
*/
|
|
117
|
-
export declare class BtcpayApiError extends PaymentProviderError {
|
|
118
|
-
readonly status: number;
|
|
119
|
-
readonly apiCode?: string;
|
|
120
|
-
constructor(message: string, status: number, apiCode?: string, options?: {
|
|
121
|
-
cause?: unknown;
|
|
122
|
-
method?: 'GET' | 'POST';
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
export declare class BtcpayClient {
|
|
126
|
-
readonly baseUrl: string;
|
|
127
|
-
readonly storeId: string;
|
|
128
|
-
private readonly apiKey;
|
|
129
|
-
private readonly fetch;
|
|
130
|
-
private readonly timeoutMs;
|
|
131
|
-
constructor(options: BtcpayClientOptions);
|
|
132
|
-
/**
|
|
133
|
-
* `POST /api/v1/stores/{storeId}/invoices`. Not idempotent at BTCPay: after
|
|
134
|
-
* a network or 5xx failure the invoice may exist, so the error is not
|
|
135
|
-
* `retryable` — look it up with `listInvoices({ orderId })` before creating
|
|
136
|
-
* another.
|
|
137
|
-
*/
|
|
138
|
-
createInvoice(input: BtcpayCreateInvoiceInput): Promise<BtcpayInvoice>;
|
|
139
|
-
/** `GET /api/v1/stores/{storeId}/invoices/{invoiceId}`. */
|
|
140
|
-
getInvoice(invoiceId: string): Promise<BtcpayInvoice>;
|
|
141
|
-
/** `GET /api/v1/stores/{storeId}/invoices` with Greenfield filters. */
|
|
142
|
-
listInvoices(input?: BtcpayListInvoicesInput): Promise<BtcpayInvoice[]>;
|
|
143
|
-
/** `GET /api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods`. */
|
|
144
|
-
getInvoicePaymentMethods(invoiceId: string): Promise<BtcpayInvoicePaymentMethod[]>;
|
|
145
|
-
private storePath;
|
|
146
|
-
private request;
|
|
147
|
-
}
|
|
148
|
-
/** A parsed BTCPay webhook delivery (signature must be verified first). */
|
|
149
|
-
export interface BtcpayWebhookDelivery {
|
|
150
|
-
deliveryId: string;
|
|
151
|
-
webhookId?: string;
|
|
152
|
-
/** Set on a redelivery: the id of the delivery it repeats. */
|
|
153
|
-
originalDeliveryId?: string;
|
|
154
|
-
isRedelivery: boolean;
|
|
155
|
-
/** `InvoiceSettled`, `InvoiceExpired`, … */
|
|
156
|
-
type: string;
|
|
157
|
-
timestamp?: Date;
|
|
158
|
-
storeId?: string;
|
|
159
|
-
invoiceId?: string;
|
|
160
|
-
metadata?: Record<string, unknown>;
|
|
161
|
-
raw: Record<string, unknown>;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Check a `BTCPay-Sig` header (`sha256=<hex>`) against the raw request body
|
|
165
|
-
* in constant time. Returns false for any missing or malformed input.
|
|
166
|
-
*/
|
|
167
|
-
export declare function isValidBtcpayWebhookSignature(rawBody: string, header: string | null | undefined, secret: string): boolean;
|
|
168
|
-
/** Parse a webhook body. Throws `PaymentProviderError` when it is malformed. */
|
|
169
|
-
export declare function parseBtcpayWebhook(rawBody: string): BtcpayWebhookDelivery;
|
|
5
|
+
export * from './btcpay-client.js';
|
|
6
|
+
export * from './btcpay-gateway.js';
|
|
170
7
|
//# sourceMappingURL=btcpay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"btcpay.d.ts","sourceRoot":"","sources":["../../src/adapters/btcpay.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"btcpay.d.ts","sourceRoot":"","sources":["../../src/adapters/btcpay.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
|