@profullstack/coinpay 0.6.11 → 0.8.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 +64 -0
- package/bin/coinpay.js +946 -59
- package/package.json +20 -3
- package/src/auth.js +2 -1
- package/src/client.d.ts +52 -0
- package/src/client.js +53 -7
- package/src/index.d.ts +34 -1
- package/src/index.js +32 -0
- package/src/invoices.d.ts +77 -0
- package/src/invoices.js +237 -0
- package/src/tokens.d.ts +14 -0
- package/src/tokens.js +34 -0
- package/src/wallet.d.ts +11 -0
- package/src/wallet.js +229 -1
- package/src/webhooks.js +37 -3
- package/src/x402-browser.js +318 -0
- package/src/x402-pay-server.js +272 -0
- package/src/x402-v2.js +416 -0
- package/src/x402.js +164 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profullstack/coinpay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet and swap support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"import": "./src/payments.js",
|
|
18
18
|
"types": "./src/payments.d.ts"
|
|
19
19
|
},
|
|
20
|
+
"./tokens": {
|
|
21
|
+
"import": "./src/tokens.js",
|
|
22
|
+
"types": "./src/tokens.d.ts"
|
|
23
|
+
},
|
|
20
24
|
"./card-payments": {
|
|
21
25
|
"import": "./src/card-payments.js",
|
|
22
26
|
"types": "./src/card-payments.d.ts"
|
|
@@ -32,6 +36,18 @@
|
|
|
32
36
|
"./swap": {
|
|
33
37
|
"import": "./src/swap.js",
|
|
34
38
|
"types": "./src/swap.d.ts"
|
|
39
|
+
},
|
|
40
|
+
"./x402": {
|
|
41
|
+
"import": "./src/x402.js"
|
|
42
|
+
},
|
|
43
|
+
"./x402-v2": {
|
|
44
|
+
"import": "./src/x402-v2.js"
|
|
45
|
+
},
|
|
46
|
+
"./x402-browser": {
|
|
47
|
+
"import": "./src/x402-browser.js"
|
|
48
|
+
},
|
|
49
|
+
"./x402-pay-server": {
|
|
50
|
+
"import": "./src/x402-pay-server.js"
|
|
35
51
|
}
|
|
36
52
|
},
|
|
37
53
|
"files": [
|
|
@@ -87,7 +103,7 @@
|
|
|
87
103
|
"node": ">=20.0.0"
|
|
88
104
|
},
|
|
89
105
|
"devDependencies": {
|
|
90
|
-
"vitest": "^
|
|
106
|
+
"vitest": "^4.1.0",
|
|
91
107
|
"eslint": "^8.57.0",
|
|
92
108
|
"prettier": "^3.4.1"
|
|
93
109
|
},
|
|
@@ -96,6 +112,7 @@
|
|
|
96
112
|
"@scure/bip39": "^1.4.0",
|
|
97
113
|
"@scure/bip32": "^1.5.0",
|
|
98
114
|
"@noble/curves": "^1.6.0",
|
|
99
|
-
"@noble/hashes": "^1.5.0"
|
|
115
|
+
"@noble/hashes": "^1.5.0",
|
|
116
|
+
"@inquirer/prompts": "^8.3.0"
|
|
100
117
|
}
|
|
101
118
|
}
|
package/src/auth.js
CHANGED
|
@@ -58,7 +58,8 @@ export async function loginMerchant(client, { email, password }) {
|
|
|
58
58
|
* @returns {Promise<Object>} Merchant information
|
|
59
59
|
*/
|
|
60
60
|
export async function getMe(client) {
|
|
61
|
+
// GET — the /auth/me endpoint is GET-only (a POST returns 405).
|
|
61
62
|
return client.request('/auth/me', {
|
|
62
|
-
method: '
|
|
63
|
+
method: 'GET',
|
|
63
64
|
});
|
|
64
65
|
}
|
package/src/client.d.ts
CHANGED
|
@@ -41,6 +41,14 @@ export interface ListPaymentsParams {
|
|
|
41
41
|
offset?: number;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/** Parameters for supported coin/token discovery */
|
|
45
|
+
export interface SupportedCoinsParams {
|
|
46
|
+
/** Business ID. Required for merchant JWTs; optional with business API keys if it matches key scope. */
|
|
47
|
+
businessId?: string;
|
|
48
|
+
/** If true, only active wallets are returned. */
|
|
49
|
+
activeOnly?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
/** Options for the `waitForPayment` polling method */
|
|
45
53
|
export interface WaitForPaymentOptions {
|
|
46
54
|
/** Polling interval in milliseconds (default: `5000`) */
|
|
@@ -109,6 +117,36 @@ export interface ListPaymentsResponse {
|
|
|
109
117
|
payments: Payment[];
|
|
110
118
|
}
|
|
111
119
|
|
|
120
|
+
/** Supported payment coin record */
|
|
121
|
+
export interface SupportedCoin {
|
|
122
|
+
symbol: string;
|
|
123
|
+
name: string;
|
|
124
|
+
is_active: boolean;
|
|
125
|
+
has_wallet: boolean;
|
|
126
|
+
wallet_source: 'business' | 'merchant_global';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Checkout token record with lower-case code accepted by createPayment currency */
|
|
130
|
+
export interface SupportedToken extends SupportedCoin {
|
|
131
|
+
code: string;
|
|
132
|
+
ticker: string;
|
|
133
|
+
chain?: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Response from supported coin discovery */
|
|
137
|
+
export interface SupportedCoinsResponse {
|
|
138
|
+
success: boolean;
|
|
139
|
+
coins: SupportedCoin[];
|
|
140
|
+
business_id: string;
|
|
141
|
+
merchant_id?: string;
|
|
142
|
+
total: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Response from token discovery */
|
|
146
|
+
export interface TokensResponse extends SupportedCoinsResponse {
|
|
147
|
+
tokens: SupportedToken[];
|
|
148
|
+
}
|
|
149
|
+
|
|
112
150
|
/**
|
|
113
151
|
* CoinPay API Client
|
|
114
152
|
*
|
|
@@ -186,6 +224,20 @@ export class CoinPayClient {
|
|
|
186
224
|
*/
|
|
187
225
|
listPayments(params: ListPaymentsParams): Promise<ListPaymentsResponse>;
|
|
188
226
|
|
|
227
|
+
/**
|
|
228
|
+
* List supported payment coins for a business.
|
|
229
|
+
*
|
|
230
|
+
* Business wallets win; merchant global wallets are used as fallback.
|
|
231
|
+
*/
|
|
232
|
+
getSupportedCoins(params?: SupportedCoinsParams): Promise<SupportedCoinsResponse>;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* List checkout-friendly tokens for a business.
|
|
236
|
+
*
|
|
237
|
+
* Returns lower-case `code` values accepted by `createPayment({ currency })`.
|
|
238
|
+
*/
|
|
239
|
+
getTokens(params?: SupportedCoinsParams): Promise<TokensResponse>;
|
|
240
|
+
|
|
189
241
|
/**
|
|
190
242
|
* Get a URL pointing to the QR code image for a payment.
|
|
191
243
|
*
|
package/src/client.js
CHANGED
|
@@ -279,6 +279,45 @@ export class CoinPayClient {
|
|
|
279
279
|
return this.request(`/payments?${params.toString()}`);
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Get supported payment coins for a business.
|
|
284
|
+
*
|
|
285
|
+
* Business API keys derive the business from the key. Passing businessId is
|
|
286
|
+
* still allowed and must match the key scope. Merchant JWTs require
|
|
287
|
+
* businessId.
|
|
288
|
+
*
|
|
289
|
+
* @param {Object} [params]
|
|
290
|
+
* @param {string} [params.businessId] - Business ID
|
|
291
|
+
* @param {boolean} [params.activeOnly] - Only return active wallets
|
|
292
|
+
* @returns {Promise<Object>} Supported coins response
|
|
293
|
+
*/
|
|
294
|
+
async getSupportedCoins({ businessId, activeOnly } = {}) {
|
|
295
|
+
const params = new URLSearchParams();
|
|
296
|
+
if (businessId) params.set('business_id', businessId);
|
|
297
|
+
if (activeOnly) params.set('active_only', 'true');
|
|
298
|
+
const query = params.toString();
|
|
299
|
+
return this.request(`/supported-coins${query ? `?${query}` : ''}`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get payment-option tokens for a business.
|
|
304
|
+
*
|
|
305
|
+
* Returns lower-case `code` values accepted by /payments/create, plus
|
|
306
|
+
* display fields for checkout coin pickers.
|
|
307
|
+
*
|
|
308
|
+
* @param {Object} [params]
|
|
309
|
+
* @param {string} [params.businessId] - Business ID
|
|
310
|
+
* @param {boolean} [params.activeOnly] - Only return active wallets
|
|
311
|
+
* @returns {Promise<Object>} Tokens response
|
|
312
|
+
*/
|
|
313
|
+
async getTokens({ businessId, activeOnly } = {}) {
|
|
314
|
+
const params = new URLSearchParams();
|
|
315
|
+
if (businessId) params.set('business_id', businessId);
|
|
316
|
+
if (activeOnly) params.set('active_only', 'true');
|
|
317
|
+
const query = params.toString();
|
|
318
|
+
return this.request(`/tokens${query ? `?${query}` : ''}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
282
321
|
/**
|
|
283
322
|
* Get payment QR code URL
|
|
284
323
|
*
|
|
@@ -685,22 +724,29 @@ export class CoinPayClient {
|
|
|
685
724
|
|
|
686
725
|
/**
|
|
687
726
|
* Create Stripe Connect onboarding link
|
|
688
|
-
*
|
|
727
|
+
*
|
|
689
728
|
* Generates a Stripe Express onboarding link for a merchant.
|
|
690
729
|
* The merchant must complete this onboarding before they can accept card payments.
|
|
691
|
-
*
|
|
730
|
+
*
|
|
731
|
+
* Country is required on the first onboarding call and is locked at Stripe
|
|
732
|
+
* account creation — it cannot be changed afterward. Subsequent calls (e.g.
|
|
733
|
+
* to finish remaining requirements) may omit it; the server reuses the
|
|
734
|
+
* country stored on the business. All Stripe Connect supported countries are
|
|
735
|
+
* accepted (US, CA, GB, AU, DE, FR, JP, SG, ...). See
|
|
736
|
+
* https://stripe.com/global for the full list.
|
|
737
|
+
*
|
|
692
738
|
* @param {string} businessId - Business ID
|
|
693
739
|
* @param {Object} [params] - Optional parameters
|
|
694
740
|
* @param {string} [params.email] - Merchant email (pre-fills onboarding form)
|
|
695
|
-
* @param {string} [params.country
|
|
741
|
+
* @param {string} [params.country] - ISO-3166-1 alpha-2 country code (e.g. 'US', 'CA', 'GB'). Required on first onboarding.
|
|
696
742
|
* @returns {Promise<Object>} Onboarding link and account ID
|
|
697
|
-
*
|
|
743
|
+
*
|
|
698
744
|
* @example
|
|
699
745
|
* const onboarding = await client.createStripeOnboardingLink('business-id', {
|
|
700
746
|
* email: 'merchant@example.com',
|
|
701
|
-
* country: '
|
|
747
|
+
* country: 'CA'
|
|
702
748
|
* });
|
|
703
|
-
*
|
|
749
|
+
*
|
|
704
750
|
* // Redirect merchant to onboarding.onboarding_url
|
|
705
751
|
*/
|
|
706
752
|
async createStripeOnboardingLink(businessId, params = {}) {
|
|
@@ -913,4 +959,4 @@ export class CoinPayClient {
|
|
|
913
959
|
}
|
|
914
960
|
}
|
|
915
961
|
|
|
916
|
-
export default CoinPayClient;
|
|
962
|
+
export default CoinPayClient;
|
package/src/index.d.ts
CHANGED
|
@@ -12,9 +12,22 @@ export type {
|
|
|
12
12
|
PaymentParams,
|
|
13
13
|
ListPaymentsParams,
|
|
14
14
|
WaitForPaymentOptions,
|
|
15
|
-
CreateBusinessParams
|
|
15
|
+
CreateBusinessParams,
|
|
16
|
+
SupportedCoinsParams,
|
|
17
|
+
SupportedCoin,
|
|
18
|
+
SupportedToken,
|
|
19
|
+
SupportedCoinsResponse,
|
|
20
|
+
TokensResponse,
|
|
16
21
|
} from './client.js';
|
|
17
22
|
|
|
23
|
+
export {
|
|
24
|
+
getTokens,
|
|
25
|
+
getSupportedCoins,
|
|
26
|
+
} from './tokens.js';
|
|
27
|
+
export type {
|
|
28
|
+
TokenDiscoveryParams,
|
|
29
|
+
} from './tokens.js';
|
|
30
|
+
|
|
18
31
|
// Payment exports
|
|
19
32
|
export {
|
|
20
33
|
createPayment,
|
|
@@ -31,6 +44,26 @@ export type {
|
|
|
31
44
|
ListPaymentsFnParams
|
|
32
45
|
} from './payments.js';
|
|
33
46
|
|
|
47
|
+
// Invoice exports
|
|
48
|
+
export {
|
|
49
|
+
createInvoice,
|
|
50
|
+
getInvoice,
|
|
51
|
+
listInvoices,
|
|
52
|
+
updateInvoice,
|
|
53
|
+
deleteInvoice,
|
|
54
|
+
sendInvoice,
|
|
55
|
+
getInvoicePaymentData,
|
|
56
|
+
InvoiceStatus,
|
|
57
|
+
} from './invoices.js';
|
|
58
|
+
export type {
|
|
59
|
+
Invoice,
|
|
60
|
+
InvoiceStatusType,
|
|
61
|
+
CreateInvoiceParams,
|
|
62
|
+
ListInvoicesParams,
|
|
63
|
+
UpdateInvoiceParams,
|
|
64
|
+
ListInvoicesResult,
|
|
65
|
+
} from './invoices.js';
|
|
66
|
+
|
|
34
67
|
// Webhook exports
|
|
35
68
|
export {
|
|
36
69
|
verifyWebhookSignature,
|
package/src/index.js
CHANGED
|
@@ -46,6 +46,11 @@ import {
|
|
|
46
46
|
PaymentStatus,
|
|
47
47
|
FiatCurrency,
|
|
48
48
|
} from './payments.js';
|
|
49
|
+
import {
|
|
50
|
+
getTokens,
|
|
51
|
+
getSupportedCoins,
|
|
52
|
+
getSupportedCoins as getSupportedPaymentCoins,
|
|
53
|
+
} from './tokens.js';
|
|
49
54
|
import {
|
|
50
55
|
verifyWebhookSignature,
|
|
51
56
|
generateWebhookSignature,
|
|
@@ -66,6 +71,18 @@ import {
|
|
|
66
71
|
authenticateEscrow,
|
|
67
72
|
} from './escrow.js';
|
|
68
73
|
|
|
74
|
+
// Invoice exports
|
|
75
|
+
import {
|
|
76
|
+
createInvoice,
|
|
77
|
+
getInvoice,
|
|
78
|
+
listInvoices,
|
|
79
|
+
updateInvoice,
|
|
80
|
+
deleteInvoice,
|
|
81
|
+
sendInvoice,
|
|
82
|
+
getInvoicePaymentData,
|
|
83
|
+
InvoiceStatus,
|
|
84
|
+
} from './invoices.js';
|
|
85
|
+
|
|
69
86
|
// Wallet exports
|
|
70
87
|
import {
|
|
71
88
|
WalletClient,
|
|
@@ -156,6 +173,7 @@ import {
|
|
|
156
173
|
verifyX402Payment,
|
|
157
174
|
settleX402Payment,
|
|
158
175
|
buildPaymentRequired,
|
|
176
|
+
expectedForProof,
|
|
159
177
|
convertUsdToAssetAmount,
|
|
160
178
|
PAYMENT_METHODS,
|
|
161
179
|
USDC_CONTRACTS,
|
|
@@ -170,6 +188,9 @@ export {
|
|
|
170
188
|
createPayment,
|
|
171
189
|
getPayment,
|
|
172
190
|
listPayments,
|
|
191
|
+
getTokens,
|
|
192
|
+
getSupportedCoins,
|
|
193
|
+
getSupportedPaymentCoins,
|
|
173
194
|
|
|
174
195
|
// Escrow functions
|
|
175
196
|
createEscrow,
|
|
@@ -182,6 +203,16 @@ export {
|
|
|
182
203
|
waitForEscrow,
|
|
183
204
|
authenticateEscrow,
|
|
184
205
|
|
|
206
|
+
// Invoice functions
|
|
207
|
+
createInvoice,
|
|
208
|
+
getInvoice,
|
|
209
|
+
listInvoices,
|
|
210
|
+
updateInvoice,
|
|
211
|
+
deleteInvoice,
|
|
212
|
+
sendInvoice,
|
|
213
|
+
getInvoicePaymentData,
|
|
214
|
+
InvoiceStatus,
|
|
215
|
+
|
|
185
216
|
// Wallet
|
|
186
217
|
WalletClient,
|
|
187
218
|
WalletChain,
|
|
@@ -263,6 +294,7 @@ export {
|
|
|
263
294
|
verifyX402Payment,
|
|
264
295
|
settleX402Payment,
|
|
265
296
|
buildPaymentRequired,
|
|
297
|
+
expectedForProof,
|
|
266
298
|
convertUsdToAssetAmount,
|
|
267
299
|
PAYMENT_METHODS,
|
|
268
300
|
USDC_CONTRACTS,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { CoinPayClient } from './client.js';
|
|
2
|
+
|
|
3
|
+
export const InvoiceStatus: {
|
|
4
|
+
readonly DRAFT: 'draft';
|
|
5
|
+
readonly SENT: 'sent';
|
|
6
|
+
readonly PAID: 'paid';
|
|
7
|
+
readonly OVERDUE: 'overdue';
|
|
8
|
+
readonly CANCELLED: 'cancelled';
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type InvoiceStatusType = (typeof InvoiceStatus)[keyof typeof InvoiceStatus];
|
|
12
|
+
|
|
13
|
+
export interface Invoice {
|
|
14
|
+
id: string;
|
|
15
|
+
invoiceNumber?: string;
|
|
16
|
+
businessId?: string;
|
|
17
|
+
clientId?: string;
|
|
18
|
+
currency?: string;
|
|
19
|
+
amount?: number;
|
|
20
|
+
cryptoCurrency?: string;
|
|
21
|
+
cryptoAmount?: string | number;
|
|
22
|
+
status?: InvoiceStatusType;
|
|
23
|
+
dueDate?: string;
|
|
24
|
+
notes?: string;
|
|
25
|
+
walletId?: string;
|
|
26
|
+
merchantWalletAddress?: string;
|
|
27
|
+
paymentAddress?: string;
|
|
28
|
+
stripeCheckoutUrl?: string;
|
|
29
|
+
paidAt?: string;
|
|
30
|
+
sentAt?: string;
|
|
31
|
+
createdAt?: string;
|
|
32
|
+
updatedAt?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CreateInvoiceParams {
|
|
36
|
+
businessId?: string;
|
|
37
|
+
clientId?: string;
|
|
38
|
+
currency: string;
|
|
39
|
+
amount: number;
|
|
40
|
+
cryptoCurrency?: string;
|
|
41
|
+
dueDate?: string;
|
|
42
|
+
notes?: string;
|
|
43
|
+
walletId?: string;
|
|
44
|
+
merchantWalletAddress?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ListInvoicesParams {
|
|
48
|
+
businessId?: string;
|
|
49
|
+
status?: InvoiceStatusType;
|
|
50
|
+
clientId?: string;
|
|
51
|
+
dateFrom?: string;
|
|
52
|
+
dateTo?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface UpdateInvoiceParams {
|
|
56
|
+
amount?: number;
|
|
57
|
+
currency?: string;
|
|
58
|
+
cryptoCurrency?: string;
|
|
59
|
+
dueDate?: string;
|
|
60
|
+
notes?: string;
|
|
61
|
+
clientId?: string;
|
|
62
|
+
walletId?: string;
|
|
63
|
+
merchantWalletAddress?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ListInvoicesResult {
|
|
67
|
+
invoices: Invoice[];
|
|
68
|
+
total?: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function createInvoice(client: CoinPayClient, options: CreateInvoiceParams): Promise<Invoice>;
|
|
72
|
+
export function listInvoices(client: CoinPayClient, filters?: ListInvoicesParams): Promise<ListInvoicesResult>;
|
|
73
|
+
export function getInvoice(client: CoinPayClient, id: string): Promise<Invoice>;
|
|
74
|
+
export function updateInvoice(client: CoinPayClient, id: string, updates: UpdateInvoiceParams): Promise<Invoice>;
|
|
75
|
+
export function deleteInvoice(client: CoinPayClient, id: string): Promise<Record<string, unknown>>;
|
|
76
|
+
export function sendInvoice(client: CoinPayClient, id: string): Promise<Record<string, unknown>>;
|
|
77
|
+
export function getInvoicePaymentData(client: CoinPayClient, id: string): Promise<Record<string, unknown>>;
|
package/src/invoices.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invoice SDK Module
|
|
3
|
+
*
|
|
4
|
+
* Create, manage, and send invoices with crypto + card payment support.
|
|
5
|
+
* Invoices can be sent to clients who pay via generated crypto addresses
|
|
6
|
+
* or optional Stripe checkout.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { CoinPayClient } from '@profullstack/coinpay';
|
|
10
|
+
* import { createInvoice, sendInvoice, getInvoicePaymentData } from '@profullstack/coinpay';
|
|
11
|
+
*
|
|
12
|
+
* const client = new CoinPayClient({ apiKey: 'your-key' });
|
|
13
|
+
*
|
|
14
|
+
* // Create an invoice
|
|
15
|
+
* const invoice = await createInvoice(client, {
|
|
16
|
+
* businessId: 'biz_123',
|
|
17
|
+
* currency: 'USD',
|
|
18
|
+
* amount: 250.00,
|
|
19
|
+
* cryptoCurrency: 'ETH',
|
|
20
|
+
* dueDate: '2026-04-01',
|
|
21
|
+
* notes: 'Web development - March 2026',
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Send it to the client
|
|
25
|
+
* const sent = await sendInvoice(client, invoice.id);
|
|
26
|
+
*
|
|
27
|
+
* // Public: get payment data (no auth)
|
|
28
|
+
* const paymentData = await getInvoicePaymentData(client, invoice.id);
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create a new invoice
|
|
33
|
+
* @param {CoinPayClient} client - API client instance
|
|
34
|
+
* @param {Object} options - Invoice parameters
|
|
35
|
+
* @param {string} [options.businessId] - Business ID (optional for business-scoped API keys)
|
|
36
|
+
* @param {string} [options.clientId] - Client ID (optional)
|
|
37
|
+
* @param {string} options.currency - Fiat currency code (USD, EUR, etc.)
|
|
38
|
+
* @param {number} options.amount - Invoice amount
|
|
39
|
+
* @param {string} [options.cryptoCurrency] - Preferred crypto for payment
|
|
40
|
+
* @param {string} [options.dueDate] - Due date (ISO string or YYYY-MM-DD)
|
|
41
|
+
* @param {string} [options.notes] - Notes / description
|
|
42
|
+
* @param {string} [options.walletId] - Wallet ID for receiving payment
|
|
43
|
+
* @param {string} [options.merchantWalletAddress] - Direct wallet address for receiving payment
|
|
44
|
+
* @returns {Promise<Object>} Created invoice
|
|
45
|
+
*/
|
|
46
|
+
export async function createInvoice(client, {
|
|
47
|
+
businessId,
|
|
48
|
+
clientId,
|
|
49
|
+
currency,
|
|
50
|
+
amount,
|
|
51
|
+
cryptoCurrency,
|
|
52
|
+
dueDate,
|
|
53
|
+
notes,
|
|
54
|
+
walletId,
|
|
55
|
+
merchantWalletAddress,
|
|
56
|
+
}) {
|
|
57
|
+
const body = {
|
|
58
|
+
business_id: businessId,
|
|
59
|
+
currency,
|
|
60
|
+
amount,
|
|
61
|
+
};
|
|
62
|
+
if (clientId) body.client_id = clientId;
|
|
63
|
+
if (cryptoCurrency) body.crypto_currency = cryptoCurrency;
|
|
64
|
+
if (dueDate) body.due_date = dueDate;
|
|
65
|
+
if (notes) body.notes = notes;
|
|
66
|
+
if (walletId) body.wallet_id = walletId;
|
|
67
|
+
if (merchantWalletAddress) body.merchant_wallet_address = merchantWalletAddress;
|
|
68
|
+
|
|
69
|
+
const data = await client.request('/invoices', {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
body: JSON.stringify(body),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return normalizeInvoice(data);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* List invoices with optional filters
|
|
79
|
+
* @param {CoinPayClient} client
|
|
80
|
+
* @param {Object} [filters]
|
|
81
|
+
* @param {string} [filters.businessId] - Filter by business ID
|
|
82
|
+
* @param {string} [filters.status] - Filter by status (draft, sent, paid, overdue, cancelled)
|
|
83
|
+
* @param {string} [filters.clientId] - Filter by client ID
|
|
84
|
+
* @param {string} [filters.dateFrom] - Filter from date (ISO string)
|
|
85
|
+
* @param {string} [filters.dateTo] - Filter to date (ISO string)
|
|
86
|
+
* @returns {Promise<Object>} { invoices, total?, ... }
|
|
87
|
+
*/
|
|
88
|
+
export async function listInvoices(client, filters = {}) {
|
|
89
|
+
const params = new URLSearchParams();
|
|
90
|
+
if (filters.businessId) params.set('business_id', filters.businessId);
|
|
91
|
+
if (filters.status) params.set('status', filters.status);
|
|
92
|
+
if (filters.clientId) params.set('client_id', filters.clientId);
|
|
93
|
+
if (filters.dateFrom) params.set('date_from', filters.dateFrom);
|
|
94
|
+
if (filters.dateTo) params.set('date_to', filters.dateTo);
|
|
95
|
+
|
|
96
|
+
const query = params.toString();
|
|
97
|
+
const endpoint = query ? `/invoices?${query}` : '/invoices';
|
|
98
|
+
const data = await client.request(endpoint);
|
|
99
|
+
|
|
100
|
+
// Handle both array and paginated responses
|
|
101
|
+
if (Array.isArray(data)) {
|
|
102
|
+
return { invoices: data.map(normalizeInvoice) };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
invoices: (data.invoices || []).map(normalizeInvoice),
|
|
107
|
+
total: data.total,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get a single invoice by ID
|
|
113
|
+
* @param {CoinPayClient} client
|
|
114
|
+
* @param {string} id - Invoice ID
|
|
115
|
+
* @returns {Promise<Object>} Invoice details
|
|
116
|
+
*/
|
|
117
|
+
export async function getInvoice(client, id) {
|
|
118
|
+
const data = await client.request(`/invoices/${encodeURIComponent(id)}`);
|
|
119
|
+
return normalizeInvoice(data);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Update an invoice
|
|
124
|
+
* @param {CoinPayClient} client
|
|
125
|
+
* @param {string} id - Invoice ID
|
|
126
|
+
* @param {Object} updates - Partial invoice fields to update
|
|
127
|
+
* @param {number} [updates.amount] - Updated amount
|
|
128
|
+
* @param {string} [updates.currency] - Updated currency
|
|
129
|
+
* @param {string} [updates.cryptoCurrency] - Updated crypto currency
|
|
130
|
+
* @param {string} [updates.dueDate] - Updated due date
|
|
131
|
+
* @param {string} [updates.notes] - Updated notes
|
|
132
|
+
* @param {string} [updates.clientId] - Updated client ID
|
|
133
|
+
* @param {string} [updates.walletId] - Updated wallet ID
|
|
134
|
+
* @param {string} [updates.merchantWalletAddress] - Updated wallet address
|
|
135
|
+
* @returns {Promise<Object>} Updated invoice
|
|
136
|
+
*/
|
|
137
|
+
export async function updateInvoice(client, id, updates) {
|
|
138
|
+
const body = {};
|
|
139
|
+
if (updates.amount !== undefined) body.amount = updates.amount;
|
|
140
|
+
if (updates.currency !== undefined) body.currency = updates.currency;
|
|
141
|
+
if (updates.cryptoCurrency !== undefined) body.crypto_currency = updates.cryptoCurrency;
|
|
142
|
+
if (updates.dueDate !== undefined) body.due_date = updates.dueDate;
|
|
143
|
+
if (updates.notes !== undefined) body.notes = updates.notes;
|
|
144
|
+
if (updates.clientId !== undefined) body.client_id = updates.clientId;
|
|
145
|
+
if (updates.walletId !== undefined) body.wallet_id = updates.walletId;
|
|
146
|
+
if (updates.merchantWalletAddress !== undefined) body.merchant_wallet_address = updates.merchantWalletAddress;
|
|
147
|
+
|
|
148
|
+
const data = await client.request(`/invoices/${encodeURIComponent(id)}`, {
|
|
149
|
+
method: 'PUT',
|
|
150
|
+
body: JSON.stringify(body),
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return normalizeInvoice(data);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Delete a draft invoice
|
|
158
|
+
* @param {CoinPayClient} client
|
|
159
|
+
* @param {string} id - Invoice ID (must be in draft status)
|
|
160
|
+
* @returns {Promise<Object>} Deletion confirmation
|
|
161
|
+
*/
|
|
162
|
+
export async function deleteInvoice(client, id) {
|
|
163
|
+
return client.request(`/invoices/${encodeURIComponent(id)}`, {
|
|
164
|
+
method: 'DELETE',
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Send an invoice to the client
|
|
170
|
+
* Generates a payment address and optional Stripe checkout link.
|
|
171
|
+
* @param {CoinPayClient} client
|
|
172
|
+
* @param {string} id - Invoice ID
|
|
173
|
+
* @returns {Promise<Object>} Send result with payment details
|
|
174
|
+
*/
|
|
175
|
+
export async function sendInvoice(client, id) {
|
|
176
|
+
const data = await client.request(`/invoices/${encodeURIComponent(id)}/send`, {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
});
|
|
179
|
+
return data;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get invoice payment data (public, no auth required)
|
|
184
|
+
* Used by clients/customers to view payment instructions.
|
|
185
|
+
* @param {CoinPayClient} client
|
|
186
|
+
* @param {string} id - Invoice ID
|
|
187
|
+
* @returns {Promise<Object>} Payment data (address, amount, status, etc.)
|
|
188
|
+
*/
|
|
189
|
+
export async function getInvoicePaymentData(client, id) {
|
|
190
|
+
const data = await client.requestUnauthenticated(`/invoices/${encodeURIComponent(id)}/pay`);
|
|
191
|
+
return data;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ── Constants ──
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Invoice status constants
|
|
198
|
+
*/
|
|
199
|
+
export const InvoiceStatus = {
|
|
200
|
+
DRAFT: 'draft',
|
|
201
|
+
SENT: 'sent',
|
|
202
|
+
PAID: 'paid',
|
|
203
|
+
OVERDUE: 'overdue',
|
|
204
|
+
CANCELLED: 'cancelled',
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// ── Helpers ──
|
|
208
|
+
|
|
209
|
+
function normalizeInvoice(data) {
|
|
210
|
+
if (!data) return data;
|
|
211
|
+
|
|
212
|
+
// Single-invoice API responses are wrapped, while older SDK callers and
|
|
213
|
+
// tests may still supply the invoice object directly.
|
|
214
|
+
const invoice = data.invoice ?? data;
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
id: invoice.id,
|
|
218
|
+
invoiceNumber: invoice.invoice_number,
|
|
219
|
+
businessId: invoice.business_id,
|
|
220
|
+
clientId: invoice.client_id,
|
|
221
|
+
currency: invoice.currency,
|
|
222
|
+
amount: invoice.amount,
|
|
223
|
+
cryptoCurrency: invoice.crypto_currency,
|
|
224
|
+
cryptoAmount: invoice.crypto_amount,
|
|
225
|
+
status: invoice.status,
|
|
226
|
+
dueDate: invoice.due_date,
|
|
227
|
+
notes: invoice.notes,
|
|
228
|
+
walletId: invoice.wallet_id,
|
|
229
|
+
merchantWalletAddress: invoice.merchant_wallet_address,
|
|
230
|
+
paymentAddress: invoice.payment_address,
|
|
231
|
+
stripeCheckoutUrl: invoice.stripe_checkout_url,
|
|
232
|
+
paidAt: invoice.paid_at,
|
|
233
|
+
sentAt: invoice.sent_at,
|
|
234
|
+
createdAt: invoice.created_at,
|
|
235
|
+
updatedAt: invoice.updated_at,
|
|
236
|
+
};
|
|
237
|
+
}
|
package/src/tokens.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CoinPayClient, SupportedCoinsParams, SupportedCoinsResponse, TokensResponse } from './client.js';
|
|
2
|
+
|
|
3
|
+
export interface TokenDiscoveryParams extends SupportedCoinsParams {
|
|
4
|
+
/** API key — required if `client` is not provided */
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/** Existing CoinPayClient instance */
|
|
7
|
+
client?: CoinPayClient;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** List checkout-friendly tokens for a business. */
|
|
11
|
+
export function getTokens(params?: TokenDiscoveryParams): Promise<TokensResponse>;
|
|
12
|
+
|
|
13
|
+
/** List supported payment coins for a business. */
|
|
14
|
+
export function getSupportedCoins(params?: TokenDiscoveryParams): Promise<SupportedCoinsResponse>;
|