@profullstack/coinpay 0.24.1 → 0.25.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/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@ All notable changes to `@profullstack/coinpay` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.25.0] - 2026-10-21
9
+
10
+ ### Added
11
+ - `createCheckoutSession({ amount, customerEmail, accountId, property, metadata, successUrl, cancelUrl, expiresInMinutes, allowedMethods })`
12
+ and `getCheckoutSession(id)`: one hosted checkout URL where the buyer picks any coin the business can
13
+ receive, or PayPal. Webhooks for the resulting payment carry `checkout_session_id`, `customer_email`,
14
+ `account_id`, `property` and `metadata`.
15
+ - `createPayment({ customerEmail, accountId, property })`, stored in the payment's metadata.
16
+
8
17
  ## [0.23.0] - 2026-10-21
9
18
 
10
19
  ### Added
package/bin/coinpay.js CHANGED
@@ -712,7 +712,8 @@ ${colors.cyan}Commands:${colors.reset}
712
712
  --with-documents: a ZIP with the period's tax documents, up to 8 MiB)
713
713
  pnl Profit and loss, personal and business as separate files
714
714
  (--scope personal|business, --months 3 (default: last 3
715
- complete months) or --from/--to, --name "Holder", --format pdf|html|csv|json)
715
+ complete months) or --from/--to, --name "Holder", --format pdf|html|csv|json,
716
+ --newest-first puts the latest month first)
716
717
  payloads [list|download <id>] Raw provider responses, exactly as received
717
718
  reports send <id> Email a report (--to a@x,b@y, --format pdf,csv, --message, --no-attach)
718
719
  books send Email the CPA pack (--to, --period, --scope, --format,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/coinpay",
3
- "version": "0.24.1",
3
+ "version": "0.25.0",
4
4
  "description": "CoinPay SDK & CLI \u2014 Accept cryptocurrency and card payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet, swap and a live finances dashboard",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/client.d.ts CHANGED
@@ -31,6 +31,57 @@ export interface PaymentParams {
31
31
  successUrl?: string;
32
32
  /** Where "Back to merchant" goes from an expired or abandoned checkout */
33
33
  cancelUrl?: string;
34
+ /** Email of the person paying; stored in metadata and sent on webhooks */
35
+ customerEmail?: string;
36
+ /** Your site's user id or handle for the payer */
37
+ accountId?: string;
38
+ /** Your site hostname */
39
+ property?: string;
40
+ }
41
+
42
+ /** Parameters for creating a hosted checkout session */
43
+ export interface CheckoutSessionParams {
44
+ /** Amount in USD */
45
+ amount: number;
46
+ /** Only `'USD'` */
47
+ currency?: 'USD';
48
+ description?: string;
49
+ /** Email of the person paying (required) */
50
+ customerEmail: string;
51
+ /** Your site's user id or handle for the payer (required) */
52
+ accountId: string;
53
+ /** Your site hostname (defaults to the business name) */
54
+ property?: string;
55
+ metadata?: Record<string, unknown>;
56
+ /** `{CHECKOUT_SESSION_ID}` and `{PAYMENT_ID}` are filled in */
57
+ successUrl?: string;
58
+ cancelUrl?: string;
59
+ /** 15 to 120, default 60 */
60
+ expiresInMinutes?: number;
61
+ /** Coin codes (e.g. `'USDC_POL'`), `'CRYPTO'` or `'PAYPAL'`; default all */
62
+ allowedMethods?: string[];
63
+ /** Only with a merchant session token; a business API key implies it */
64
+ businessId?: string;
65
+ }
66
+
67
+ /** Response from `createCheckoutSession` */
68
+ export interface CheckoutSessionResponse {
69
+ success: boolean;
70
+ id: string;
71
+ url: string;
72
+ status: 'open' | 'paid' | 'expired';
73
+ amount: number;
74
+ currency: 'USD';
75
+ description: string | null;
76
+ customer_email: string;
77
+ account_id: string;
78
+ property: string;
79
+ metadata: Record<string, unknown>;
80
+ success_url: string | null;
81
+ cancel_url: string | null;
82
+ expires_at: string;
83
+ methods: string[];
84
+ [key: string]: unknown;
34
85
  }
35
86
 
36
87
  /** Parameters for listing payments */
@@ -200,6 +251,15 @@ export class CoinPayClient {
200
251
  */
201
252
  createPayment(params: PaymentParams): Promise<CreatePaymentResponse>;
202
253
 
254
+ /**
255
+ * Create a hosted checkout session; redirect the buyer to `url`. The buyer
256
+ * picks any coin the business can receive, or PayPal.
257
+ */
258
+ createCheckoutSession(params: CheckoutSessionParams): Promise<CheckoutSessionResponse>;
259
+
260
+ /** Get a checkout session (`cs_...`). */
261
+ getCheckoutSession(sessionId: string): Promise<Record<string, unknown>>;
262
+
203
263
  /**
204
264
  * Get payment details by ID.
205
265
  *
package/src/client.js CHANGED
@@ -255,6 +255,9 @@ export class CoinPayClient {
255
255
  metadata,
256
256
  successUrl,
257
257
  cancelUrl,
258
+ customerEmail,
259
+ accountId,
260
+ property,
258
261
  }) {
259
262
  // Map to API field names (snake_case)
260
263
  return this.request('/payments/create', {
@@ -268,10 +271,90 @@ export class CoinPayClient {
268
271
  metadata,
269
272
  success_url: successUrl,
270
273
  cancel_url: cancelUrl,
274
+ customer_email: customerEmail,
275
+ account_id: accountId,
276
+ property,
271
277
  }),
272
278
  });
273
279
  }
274
280
 
281
+ /**
282
+ * Create a hosted checkout session.
283
+ *
284
+ * Redirect the buyer to the returned `url`. There they choose any coin your
285
+ * business has a wallet for (stablecoins first) or PayPal when connected.
286
+ * The payment and every webhook for it carry `checkout_session_id`,
287
+ * `customer_email`, `account_id`, `property` and your `metadata`.
288
+ *
289
+ * @param {Object} params
290
+ * @param {number} params.amount - Amount in USD
291
+ * @param {string} params.customerEmail - Email of the person paying (required)
292
+ * @param {string} params.accountId - Your site's user id or handle for the payer (required)
293
+ * @param {string} [params.property] - Your site hostname (defaults to the business name)
294
+ * @param {string} [params.description]
295
+ * @param {Object} [params.metadata]
296
+ * @param {string} [params.successUrl] - `{CHECKOUT_SESSION_ID}` and `{PAYMENT_ID}` are filled in
297
+ * @param {string} [params.cancelUrl]
298
+ * @param {number} [params.expiresInMinutes=60] - 15 to 120
299
+ * @param {string[]} [params.allowedMethods] - coin codes, 'CRYPTO' or 'PAYPAL' (default: all)
300
+ * @returns {Promise<{success: boolean, id: string, url: string, status: string, expires_at: string, methods: string[]}>}
301
+ *
302
+ * @example
303
+ * const { id, url } = await client.createCheckoutSession({
304
+ * amount: 9.99,
305
+ * description: 'Pro plan',
306
+ * customerEmail: 'buyer@example.com',
307
+ * accountId: 'user_123',
308
+ * property: 'example.com',
309
+ * successUrl: 'https://example.com/thanks?session={CHECKOUT_SESSION_ID}',
310
+ * cancelUrl: 'https://example.com/pricing',
311
+ * });
312
+ * // res.redirect(url)
313
+ */
314
+ async createCheckoutSession({
315
+ amount,
316
+ currency = 'USD',
317
+ description,
318
+ customerEmail,
319
+ accountId,
320
+ property,
321
+ metadata,
322
+ successUrl,
323
+ cancelUrl,
324
+ expiresInMinutes,
325
+ allowedMethods,
326
+ businessId,
327
+ }) {
328
+ return this.request('/checkout/sessions', {
329
+ method: 'POST',
330
+ body: JSON.stringify({
331
+ amount,
332
+ currency,
333
+ description,
334
+ customer_email: customerEmail,
335
+ account_id: accountId,
336
+ property,
337
+ metadata,
338
+ success_url: successUrl,
339
+ cancel_url: cancelUrl,
340
+ expires_in_minutes: expiresInMinutes,
341
+ allowed_methods: allowedMethods,
342
+ business_id: businessId,
343
+ }),
344
+ });
345
+ }
346
+
347
+ /**
348
+ * Get a checkout session. With your business API key the response includes
349
+ * the customer fields, metadata and the underlying payment ids.
350
+ *
351
+ * @param {string} sessionId - `cs_...`
352
+ * @returns {Promise<Object>} `{ success, session }`
353
+ */
354
+ async getCheckoutSession(sessionId) {
355
+ return this.request(`/checkout/sessions/${encodeURIComponent(sessionId)}`);
356
+ }
357
+
275
358
  /**
276
359
  * Get payment by ID
277
360
  *
@@ -816,9 +816,10 @@ export async function runFinancesCommand(subcommand, args, flags, ctx) {
816
816
  const to = typeof flags.to === 'string' ? flags.to : undefined;
817
817
  const timezone = typeof flags.timezone === 'string' ? flags.timezone : undefined;
818
818
  const name = typeof flags.name === 'string' ? flags.name : undefined;
819
+ const order = flags['newest-first'] === true ? 'newest' : typeof flags.order === 'string' ? flags.order : undefined;
819
820
  const written = [];
820
821
  for (const scope of wanted) {
821
- const file = await api.exportPnl(client, { scope, months, period, from, to, timezone, name, format });
822
+ const file = await api.exportPnl(client, { scope, months, period, from, to, timezone, name, format, order });
822
823
  const output = typeof flags.output === 'string' && wanted.length === 1 ? flags.output : file.filename || `pnl-${scope}.${format}`;
823
824
  written.push({ scope, output: writeDownload(output, Buffer.from(file.bytes), { overwrite: flags.overwrite === true }), bytes: file.bytes.length });
824
825
  }
@@ -403,8 +403,8 @@ export async function exportBooks(client, { period, from, to, timezone, scope, f
403
403
  * Profit and loss statement for one scope. With no period it covers the
404
404
  * last `months` complete calendar months (server default 3).
405
405
  */
406
- export async function exportPnl(client, { scope, months, period, from, to, timezone, name, format = 'pdf' } = {}) {
407
- return client.requestBinary(`/finances/pnl${query({ scope, months, period, from, to, timezone, name, format })}`);
406
+ export async function exportPnl(client, { scope, months, period, from, to, timezone, name, format = 'pdf', order } = {}) {
407
+ return client.requestBinary(`/finances/pnl${query({ scope, months, period, from, to, timezone, name, format, order })}`);
408
408
  }
409
409
 
410
410
  // ── Raw provider payloads ──