@molecule/api-payments-stripe 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/README.md +920 -0
  2. package/package.json +8 -7
package/README.md ADDED
@@ -0,0 +1,920 @@
1
+ <!--
2
+ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
+ Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
+ Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
+ To change this document, edit the module-level JSDoc in src/index.ts.
6
+ Generated: 2026-08-04T01:48:53.204Z
7
+ -->
8
+
9
+ # @molecule/api-payments-stripe
10
+
11
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
+ > It is written to be read by coding agents as much as by people, and is generated from this
13
+ > package's source — edit `src/index.ts` JSDoc, not this file.
14
+
15
+ Stripe payment provider for molecule.dev.
16
+
17
+ ## Type
18
+
19
+ `provider`
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @molecule/api-payments-stripe @molecule/api-bond @molecule/api-i18n @molecule/api-jwt @molecule/api-payments @molecule/api-secrets stripe
25
+ ```
26
+
27
+ ## API
28
+
29
+ ### Interfaces
30
+
31
+ #### `AccountStatus`
32
+
33
+ Connected-account onboarding / payout eligibility status.
34
+
35
+ ```typescript
36
+ interface AccountStatus {
37
+ /** Stripe connected account ID. */
38
+ id: string
39
+ /** Whether the account can accept charges. */
40
+ chargesEnabled: boolean
41
+ /** Whether the account can receive payouts. */
42
+ payoutsEnabled: boolean
43
+ /** Whether there are any currently-due requirements (Stripe is blocked on something). */
44
+ requirementsCurrent: boolean
45
+ /** Stripe connected-account type (`standard`, `express`, `custom`), if known. */
46
+ type?: ConnectedAccountType
47
+ /** Currently-due requirement IDs from Stripe (empty when nothing is due). */
48
+ currentlyDue: readonly string[]
49
+ }
50
+ ```
51
+
52
+ #### `CheckoutSessionResult`
53
+
54
+ Result of creating or retrieving a checkout session.
55
+
56
+ ```typescript
57
+ interface CheckoutSessionResult {
58
+ id: string
59
+ url: string | null
60
+ /** The Stripe Subscription ID created by the checkout session, if available. */
61
+ subscription?: string
62
+ }
63
+ ```
64
+
65
+ #### `ConnectedAccountBusinessProfile`
66
+
67
+ Subset of Stripe `business_profile` fields commonly set during marketplace
68
+ onboarding.
69
+
70
+ ```typescript
71
+ interface ConnectedAccountBusinessProfile {
72
+ name?: string
73
+ url?: string
74
+ productDescription?: string
75
+ supportEmail?: string
76
+ supportPhone?: string
77
+ mcc?: string
78
+ }
79
+ ```
80
+
81
+ #### `ConnectWebhookEvent`
82
+
83
+ Normalized Connect webhook event.
84
+
85
+ Provider-agnostic shape so consumers don't have to import Stripe types
86
+ to dispatch on event kind.
87
+
88
+ ```typescript
89
+ interface ConnectWebhookEvent {
90
+ /** Recognized Connect event type, or `unknown` for unrelated events. */
91
+ type: ConnectWebhookEventType
92
+ /** Original Stripe event type string (e.g. `account.updated`). */
93
+ rawType: string
94
+ /** The ID of the primary resource this event is about (account, payout, transfer, fee). */
95
+ resourceId?: string
96
+ /** The connected account this event applies to, if Stripe sent one. */
97
+ accountId?: string
98
+ /** Raw event-data object (plain JSON shape — never the live Stripe object). */
99
+ data: Record<string, unknown>
100
+ }
101
+ ```
102
+
103
+ #### `CreateAccountLinkParams`
104
+
105
+ Parameters for creating an account link.
106
+
107
+ ```typescript
108
+ interface CreateAccountLinkParams {
109
+ /** Stripe connected account ID (`acct_...`). */
110
+ accountId: string
111
+ /** URL Stripe redirects the user back to after onboarding completes. */
112
+ returnUrl: string
113
+ /** URL Stripe redirects the user to if the link expires before completion. */
114
+ refreshUrl: string
115
+ /** Whether this is a first-time onboarding link or an update link. */
116
+ type: AccountLinkType
117
+ /** Optional idempotency key for safe retries. */
118
+ idempotencyKey?: string
119
+ }
120
+ ```
121
+
122
+ #### `CreateAccountLinkResult`
123
+
124
+ Result of creating an account link.
125
+
126
+ ```typescript
127
+ interface CreateAccountLinkResult {
128
+ /** Hosted onboarding URL the connected account holder should open. */
129
+ url: string
130
+ /** Unix timestamp (seconds) when the link expires. */
131
+ expiresAt: number
132
+ }
133
+ ```
134
+
135
+ #### `CreateConnectedAccountParams`
136
+
137
+ Parameters for creating a connected account.
138
+
139
+ ```typescript
140
+ interface CreateConnectedAccountParams {
141
+ /** Stripe account type — `standard`, `express`, or `custom`. */
142
+ type: ConnectedAccountType
143
+ /** Two-letter ISO country code for the account holder (e.g. `US`, `GB`). */
144
+ country: string
145
+ /** Email address of the account holder. */
146
+ email: string
147
+ /** Optional business profile fields (display name, website, MCC, etc.). */
148
+ businessProfile?: ConnectedAccountBusinessProfile
149
+ /** Optional metadata to attach to the connected account. */
150
+ metadata?: Record<string, string>
151
+ /** Optional idempotency key for safe retries. */
152
+ idempotencyKey?: string
153
+ }
154
+ ```
155
+
156
+ #### `CreateConnectedAccountResult`
157
+
158
+ Result of creating a connected account.
159
+
160
+ ```typescript
161
+ interface CreateConnectedAccountResult {
162
+ /** Stripe connected account ID (`acct_...`). */
163
+ id: string
164
+ /** Optional onboarding URL (only present when an account link is created in the same flow). */
165
+ accountLinkUrl?: string
166
+ }
167
+ ```
168
+
169
+ #### `CreatePayoutParams`
170
+
171
+ Parameters for creating a payout from a connected account's Stripe balance to its bank account.
172
+
173
+ ```typescript
174
+ interface CreatePayoutParams {
175
+ /** Connected account ID to issue the payout from (`acct_...`). */
176
+ accountId: string
177
+ /** Amount in the smallest currency unit (e.g. cents for USD). */
178
+ amount: number
179
+ /** Three-letter ISO currency code, lowercase (e.g. `usd`). */
180
+ currency: string
181
+ /** Optional payout method — `standard` or `instant`. */
182
+ method?: 'standard' | 'instant'
183
+ /** Optional metadata. */
184
+ metadata?: Record<string, string>
185
+ /** Optional idempotency key for safe retries. */
186
+ idempotencyKey?: string
187
+ }
188
+ ```
189
+
190
+ #### `CreatePayoutResult`
191
+
192
+ Result of creating a payout.
193
+
194
+ ```typescript
195
+ interface CreatePayoutResult {
196
+ /** Stripe payout ID (`po_...`). */
197
+ id: string
198
+ /** Amount paid out (smallest currency unit). */
199
+ amount: number
200
+ /** Three-letter ISO currency code. */
201
+ currency: string
202
+ /** Payout status (e.g. `pending`, `paid`, `failed`). */
203
+ status: string
204
+ /** Estimated arrival date (Unix timestamp in seconds). */
205
+ arrivalDate: number
206
+ }
207
+ ```
208
+
209
+ #### `CreateTransferParams`
210
+
211
+ Parameters for creating a transfer to a connected account.
212
+
213
+ ```typescript
214
+ interface CreateTransferParams {
215
+ /** Amount in the smallest currency unit (e.g. cents for USD). */
216
+ amount: number
217
+ /** Three-letter ISO currency code, lowercase (e.g. `usd`). */
218
+ currency: string
219
+ /** Destination connected account ID (`acct_...`). */
220
+ destination: string
221
+ /** Optional source charge to attach the transfer to (for separate-charges-and-transfers flow). */
222
+ sourceTransaction?: string
223
+ /** Optional transfer group string (groups related transfers/charges together). */
224
+ transferGroup?: string
225
+ /** Optional metadata. */
226
+ metadata?: Record<string, string>
227
+ /** Optional idempotency key for safe retries. */
228
+ idempotencyKey?: string
229
+ }
230
+ ```
231
+
232
+ #### `CreateTransferResult`
233
+
234
+ Result of creating a transfer.
235
+
236
+ ```typescript
237
+ interface CreateTransferResult {
238
+ /** Stripe transfer ID (`tr_...`). */
239
+ id: string
240
+ /** Amount transferred (smallest currency unit). */
241
+ amount: number
242
+ /** Three-letter ISO currency code. */
243
+ currency: string
244
+ /** Destination connected account ID. */
245
+ destination: string
246
+ /** Transfer group, if set. */
247
+ transferGroup?: string
248
+ }
249
+ ```
250
+
251
+ #### `NormalizedPurchase`
252
+
253
+ Normalized purchase information (for one-time purchases).
254
+
255
+ ```typescript
256
+ interface NormalizedPurchase {
257
+ /**
258
+ * The payment provider.
259
+ */
260
+ provider: PaymentProviderName
261
+ /**
262
+ * The purchase/transaction ID.
263
+ */
264
+ purchaseId: string
265
+ /**
266
+ * The product ID.
267
+ */
268
+ productId: string
269
+ /**
270
+ * Whether the purchase is valid.
271
+ */
272
+ isValid: boolean
273
+ /**
274
+ * When the purchase was made (Unix timestamp in ms).
275
+ */
276
+ purchaseDate: number
277
+ /**
278
+ * Raw data from the provider.
279
+ */
280
+ rawData: unknown
281
+ }
282
+ ```
283
+
284
+ #### `NormalizedSubscription`
285
+
286
+ Normalized subscription information.
287
+
288
+ Use this interface to abstract away provider-specific differences.
289
+
290
+ ```typescript
291
+ interface NormalizedSubscription {
292
+ /**
293
+ * The payment provider.
294
+ */
295
+ provider: PaymentProviderName
296
+ /**
297
+ * The subscription ID from the provider.
298
+ */
299
+ subscriptionId: string
300
+ /**
301
+ * The product/plan ID.
302
+ */
303
+ productId: string
304
+ /**
305
+ * Current subscription status.
306
+ */
307
+ status: SubscriptionStatus
308
+ /**
309
+ * Whether the subscription is currently active.
310
+ */
311
+ isActive: boolean
312
+ /**
313
+ * When the current period started (Unix timestamp in ms).
314
+ */
315
+ currentPeriodStart?: number
316
+ /**
317
+ * When the current period ends (Unix timestamp in ms).
318
+ */
319
+ currentPeriodEnd?: number
320
+ /**
321
+ * Whether the subscription will auto-renew.
322
+ */
323
+ willRenew?: boolean
324
+ /**
325
+ * When the subscription was canceled (if applicable).
326
+ */
327
+ canceledAt?: number
328
+ /**
329
+ * Raw data from the provider.
330
+ */
331
+ rawData: unknown
332
+ }
333
+ ```
334
+
335
+ #### `SubscriptionResult`
336
+
337
+ Normalized subscription data from Stripe.
338
+
339
+ ```typescript
340
+ interface SubscriptionResult {
341
+ id: string
342
+ status: string
343
+ /**
344
+ * The Stripe Customer ID (`cus_...`) that owns this subscription. Used to bind
345
+ * a verified subscription to the calling user so a foreign subscription id
346
+ * cannot be claimed (ownership check in `verifyPayment`).
347
+ */
348
+ customer?: string
349
+ items: { data: Array<{ id: string; price?: { id?: string; product?: string } }> }
350
+ current_period_start: number
351
+ current_period_end: number
352
+ cancel_at_period_end: boolean
353
+ canceled_at: number | null
354
+ }
355
+ ```
356
+
357
+ #### `SubscriptionUpdateParams`
358
+
359
+ Parameters for updating a subscription.
360
+
361
+ ```typescript
362
+ interface SubscriptionUpdateParams {
363
+ items?: Array<{ id: string; price: string }>
364
+ cancel_at_period_end?: boolean
365
+ }
366
+ ```
367
+
368
+ #### `WebhookEventResult`
369
+
370
+ Result of verifying a webhook event.
371
+
372
+ ```typescript
373
+ interface WebhookEventResult {
374
+ type: string
375
+ data: { object: Record<string, unknown> }
376
+ }
377
+ ```
378
+
379
+ ### Types
380
+
381
+ #### `AccountLinkType`
382
+
383
+ Account-link types — onboarding (first-time) vs update (returning).
384
+
385
+ ```typescript
386
+ type AccountLinkType = 'account_onboarding' | 'account_update'
387
+ ```
388
+
389
+ #### `ConnectedAccountType`
390
+
391
+ Connected account type.
392
+
393
+ Stripe distinguishes three account types with different
394
+ onboarding / dashboard responsibilities. See
395
+ https://stripe.com/docs/connect/accounts.
396
+
397
+ ```typescript
398
+ type ConnectedAccountType = 'standard' | 'express' | 'custom'
399
+ ```
400
+
401
+ #### `ConnectWebhookEventType`
402
+
403
+ Connect webhook event types this provider knows how to interpret.
404
+
405
+ `unknown` is returned for any other Stripe event so callers can fall
406
+ through to the standard subscription webhook handler if needed.
407
+
408
+ ```typescript
409
+ type ConnectWebhookEventType =
410
+ 'account.updated' | 'payout.created' | 'transfer.created' | 'application_fee.refunded' | 'unknown'
411
+ ```
412
+
413
+ #### `PaymentProvider`
414
+
415
+ Payment provider bond interface.
416
+
417
+ Each payment provider implements the methods relevant to its platform.
418
+ All methods are optional since different platforms use different flows.
419
+
420
+ ```typescript
421
+ type PaymentProvider = PaymentProviderInterface
422
+ ```
423
+
424
+ #### `SubscriptionStatus`
425
+
426
+ Subscription status across providers.
427
+
428
+ ```typescript
429
+ type SubscriptionStatus =
430
+ 'active' | 'canceled' | 'expired' | 'past_due' | 'trialing' | 'paused' | 'pending' | 'unknown'
431
+ ```
432
+
433
+ ### Functions
434
+
435
+ #### `cancelSubscription(subscriptionId)`
436
+
437
+ Immediately cancels a Stripe subscription.
438
+
439
+ ```typescript
440
+ function cancelSubscription(subscriptionId: string): Promise<SubscriptionResult>
441
+ ```
442
+
443
+ - `subscriptionId` — The Stripe subscription ID to cancel.
444
+
445
+ **Returns:** The canceled subscription result.
446
+
447
+ #### `createAccountLink(params)`
448
+
449
+ Creates a Stripe account link the connected account holder uses to finish
450
+ onboarding (or to update payout details).
451
+
452
+ ```typescript
453
+ function createAccountLink(params: CreateAccountLinkParams): Promise<CreateAccountLinkResult>
454
+ ```
455
+
456
+ - `params` — Account-link creation parameters.
457
+
458
+ **Returns:** The hosted onboarding/update URL and its expiry (Unix timestamp, seconds).
459
+
460
+ #### `createCheckoutSession(options)`
461
+
462
+ Creates a Stripe Checkout session for a new subscription.
463
+
464
+ ```typescript
465
+ function createCheckoutSession(options: {
466
+ priceId: string
467
+ successUrl: string
468
+ cancelUrl: string
469
+ customerId?: string
470
+ metadata?: Record<string, string>
471
+ idempotencyKey?: string
472
+ }): Promise<CheckoutSessionResult>
473
+ ```
474
+
475
+ - `options` — Checkout configuration.
476
+ - `options.priceId` — The Stripe Price ID for the subscription line item.
477
+ - `options.successUrl` — URL to redirect to after successful payment.
478
+ - `options.cancelUrl` — URL to redirect to if the user cancels.
479
+ - `options.customerId` — Optional existing Stripe Customer ID.
480
+ - `options.metadata` — Optional key-value metadata to attach to the session.
481
+ - `options.idempotencyKey` — Optional idempotency key for safe request retries.
482
+
483
+ **Returns:** The checkout session ID and URL.
484
+
485
+ #### `createConnectedAccount(params)`
486
+
487
+ Creates a Stripe connected account for a marketplace seller / driver / provider.
488
+
489
+ ```typescript
490
+ function createConnectedAccount(
491
+ params: CreateConnectedAccountParams,
492
+ ): Promise<CreateConnectedAccountResult>
493
+ ```
494
+
495
+ - `params` — Connected-account creation parameters.
496
+
497
+ **Returns:** The new account ID.
498
+
499
+ #### `createPayout(params)`
500
+
501
+ Issues a payout from a connected account's Stripe balance to its bank account.
502
+
503
+ Uses Stripe's `Stripe-Account` header to scope the call to the connected account.
504
+
505
+ ```typescript
506
+ function createPayout(params: CreatePayoutParams): Promise<CreatePayoutResult>
507
+ ```
508
+
509
+ - `params` — Payout parameters.
510
+
511
+ **Returns:** The created payout.
512
+
513
+ #### `createPortalSession(options)`
514
+
515
+ Creates a Stripe Billing Portal session so the user can manage their
516
+ subscription (update payment method, cancel, view invoices) in Stripe's
517
+ hosted portal.
518
+
519
+ ```typescript
520
+ function createPortalSession(options: {
521
+ customerId: string
522
+ returnUrl?: string
523
+ }): Promise<{ id: string; url: string } | null>
524
+ ```
525
+
526
+ - `options` — Portal configuration.
527
+ - `options.customerId` — The Stripe Customer ID to open the portal for.
528
+ - `options.returnUrl` — URL Stripe returns the user to when they exit the portal. Falls back to APP_ORIGIN/ORIGIN when omitted.
529
+
530
+ **Returns:** The portal session ID and URL, or `null` when Stripe rejects the request (e.g. unknown customer).
531
+
532
+ #### `createSetupIntent(options)`
533
+
534
+ Creates a Stripe SetupIntent for the saved-card flow.
535
+
536
+ If `customerId` is not provided, a new Stripe customer is created and its
537
+ ID is returned alongside the SetupIntent so the resource layer can persist
538
+ the customer ID for future SetupIntents and detachments.
539
+
540
+ ```typescript
541
+ function createSetupIntent(options: {
542
+ customerId?: string
543
+ metadata?: Record<string, string>
544
+ idempotencyKey?: string
545
+ }): Promise<{ id: string; clientSecret: string; customerId: string }>
546
+ ```
547
+
548
+ - `options` — SetupIntent creation options.
549
+ - `options.customerId` — Optional existing Stripe customer ID (`cus_...`).
550
+ - `options.metadata` — Optional metadata to attach to the SetupIntent.
551
+ - `options.idempotencyKey` — Optional idempotency key for safe retries.
552
+
553
+ **Returns:** The SetupIntent ID, client secret, and customer ID.
554
+
555
+ #### `createTransfer(params)`
556
+
557
+ Transfers funds from the platform balance to a connected account.
558
+
559
+ ```typescript
560
+ function createTransfer(params: CreateTransferParams): Promise<CreateTransferResult>
561
+ ```
562
+
563
+ - `params` — Transfer parameters.
564
+
565
+ **Returns:** The created transfer.
566
+
567
+ #### `detachPaymentMethod(paymentMethodId)`
568
+
569
+ Detaches a saved Stripe payment method from its customer.
570
+
571
+ ```typescript
572
+ function detachPaymentMethod(paymentMethodId: string): Promise<boolean>
573
+ ```
574
+
575
+ - `paymentMethodId` — The Stripe payment method ID (`pm_...`).
576
+
577
+ **Returns:** `true` if Stripe acknowledged the detach, `false` otherwise.
578
+
579
+ #### `getAccountStatus(accountId)`
580
+
581
+ Looks up a connected account's onboarding / payout status.
582
+
583
+ ```typescript
584
+ function getAccountStatus(accountId: string): Promise<AccountStatus>
585
+ ```
586
+
587
+ - `accountId` — Stripe connected account ID (`acct_...`).
588
+
589
+ **Returns:** Normalized account status.
590
+
591
+ #### `getCheckoutSession(sessionId)`
592
+
593
+ Retrieves a Stripe Checkout session by ID, including the associated subscription.
594
+
595
+ ```typescript
596
+ function getCheckoutSession(sessionId: string): Promise<CheckoutSessionResult>
597
+ ```
598
+
599
+ - `sessionId` — The Stripe Checkout session ID.
600
+
601
+ **Returns:** The session ID, URL, and subscription ID (if a subscription was created).
602
+
603
+ #### `getClient()`
604
+
605
+ Returns the lazily-initialized Stripe client. Throws if `STRIPE_SECRET_KEY` is not set.
606
+
607
+ ```typescript
608
+ function getClient(): Stripe
609
+ ```
610
+
611
+ **Returns:** The shared `Stripe` SDK instance.
612
+
613
+ #### `getSubscription(subscriptionId)`
614
+
615
+ Retrieves a Stripe subscription by ID with expanded item data.
616
+
617
+ ```typescript
618
+ function getSubscription(subscriptionId: string): Promise<SubscriptionResult>
619
+ ```
620
+
621
+ - `subscriptionId` — The Stripe subscription ID.
622
+
623
+ **Returns:** The normalized subscription result.
624
+
625
+ #### `normalizeSubscription(subscription)`
626
+
627
+ Normalizes a Stripe-specific `SubscriptionResult` to the common
628
+ `NormalizedSubscription` interface used across all payment providers.
629
+
630
+ ```typescript
631
+ function normalizeSubscription(subscription: SubscriptionResult): NormalizedSubscription
632
+ ```
633
+
634
+ - `subscription` — The Stripe subscription result to normalize.
635
+
636
+ **Returns:** A `NormalizedSubscription` with provider-agnostic fields.
637
+
638
+ #### `normalizeSubscriptionStatus(rawStatus)`
639
+
640
+ Maps a raw Stripe subscription status string (e.g. `past_due`, `incomplete`)
641
+ to the provider-agnostic `SubscriptionStatus`.
642
+
643
+ Shared between `normalizeSubscription` (verify path) and the webhook adapter so
644
+ both paths derive status identically.
645
+
646
+ ```typescript
647
+ function normalizeSubscriptionStatus(rawStatus: string | undefined): SubscriptionStatus
648
+ ```
649
+
650
+ - `rawStatus` — The raw Stripe `status` string, or `undefined` if absent.
651
+
652
+ **Returns:** The normalized `SubscriptionStatus` (`'unknown'` for unrecognized/missing).
653
+
654
+ #### `processConnectWebhook(headers, body)`
655
+
656
+ Verifies and normalizes a Stripe Connect webhook event.
657
+
658
+ Reuses the same `STRIPE_WEBHOOK_SECRET` env var as the standard webhook
659
+ pipeline (and the same signature verification logic) — Connect events
660
+ arrive on the same webhook endpoint when the platform's webhook is
661
+ configured to receive Connect events.
662
+
663
+ ```typescript
664
+ function processConnectWebhook(
665
+ headers: Record<string, string | string[] | undefined>,
666
+ body: string | Buffer<ArrayBufferLike>,
667
+ ): ConnectWebhookEvent
668
+ ```
669
+
670
+ - `headers` — Request headers (looks up `stripe-signature`).
671
+ - `body` — The raw request body (string or Buffer).
672
+
673
+ **Returns:** The verified, normalized Connect webhook event.
674
+
675
+ #### `reportUsageOverage(options)`
676
+
677
+ Reports a usage-based OVERAGE charge to Stripe as a one-off invoice item
678
+ against an existing customer (and, when given, attached to the open invoice
679
+ of a specific subscription so it lands on the next cycle invoice).
680
+
681
+ This is the supported, type-safe path on the installed Stripe SDK (v22):
682
+ the legacy `subscriptionItems.createUsageRecord` API was removed in favor of
683
+ metered-price meter events / invoice items. A positive-amount invoice item
684
+ is the simplest cost-plus overage mechanism — Stripe aggregates open invoice
685
+ items and bills them at the customer's cycle close, so repeated incremental
686
+ calls accrete onto the same upcoming invoice.
687
+
688
+ IDEMPOTENCY: the caller MUST pass a stable `idempotencyKey` derived from
689
+ `(user, period, amount)` so a retry or a double-run within the same Stripe
690
+ idempotency window (24h) is collapsed to a single invoice item and never
691
+ double-charges (broker safety invariant 4).
692
+
693
+ This function performs NO gating of its own — it charges whatever it is
694
+ told to. The decision of WHETHER to charge (configured? opted-in? paid?
695
+ over budget?) lives entirely in the molecule-dev billing module, which is
696
+ the single inert/opt-in gate (safety invariants 1 + 2).
697
+
698
+ ```typescript
699
+ function reportUsageOverage(options: {
700
+ customerId: string
701
+ amountCents: number
702
+ currency?: string
703
+ priceId: string
704
+ subscriptionId?: string
705
+ description?: string
706
+ metadata?: Record<string, string>
707
+ idempotencyKey: string
708
+ }): Promise<{ id: string; amountCents: number }>
709
+ ```
710
+
711
+ - `options` — Overage reporting options.
712
+ - `options.customerId` — The Stripe customer to bill (`cus_...`).
713
+ - `options.amountCents` — The overage amount in cents (must be `> 0`).
714
+ - `options.currency` — ISO currency (defaults to `usd`).
715
+ - `options.priceId` — The metered/overage Price id this reports against; recorded in metadata for reconciliation (the invoice item carries an explicit `amount`, so the price's unit amount is not used here).
716
+ - `options.subscriptionId` — Optional subscription to attach the item to so it bills on that subscription's cycle invoice.
717
+ - `options.description` — Human-readable line description.
718
+ - `options.metadata` — Extra reconciliation metadata (e.g. period).
719
+ - `options.idempotencyKey` — REQUIRED stable key (see IDEMPOTENCY above).
720
+
721
+ **Returns:** The created invoice item id + the amount actually reported.
722
+
723
+ #### `retrievePaymentMethod(paymentMethodId)`
724
+
725
+ Retrieves a saved Stripe payment method (card) and returns normalized metadata.
726
+
727
+ ```typescript
728
+ function retrievePaymentMethod(
729
+ paymentMethodId: string,
730
+ ): Promise<{ id: string; brand: string; last4: string; expMonth: number; expYear: number } | null>
731
+ ```
732
+
733
+ - `paymentMethodId` — The Stripe payment method ID (`pm_...`).
734
+
735
+ **Returns:** Brand, last4, and expiry, or `null` if the lookup fails.
736
+
737
+ #### `updateSubscription(subscriptionId, params)`
738
+
739
+ Updates a Stripe subscription (e.g. changes plan, sets cancel_at_period_end).
740
+
741
+ ```typescript
742
+ function updateSubscription(
743
+ subscriptionId: string,
744
+ params: SubscriptionUpdateParams,
745
+ ): Promise<SubscriptionResult>
746
+ ```
747
+
748
+ - `subscriptionId` — The Stripe subscription ID to update.
749
+ - `params` — The Stripe subscription update parameters.
750
+
751
+ **Returns:** The updated subscription result.
752
+
753
+ #### `verifyWebhookSignature(payload, signature)`
754
+
755
+ Verifies a Stripe webhook signature and parses the event payload.
756
+ Requires `STRIPE_WEBHOOK_SECRET` env var.
757
+
758
+ ```typescript
759
+ function verifyWebhookSignature(
760
+ payload: string | Buffer<ArrayBufferLike>,
761
+ signature: string,
762
+ ): WebhookEventResult
763
+ ```
764
+
765
+ - `payload` — The raw request body (string or Buffer).
766
+ - `signature` — The `stripe-signature` header value.
767
+
768
+ **Returns:** The verified webhook event with type and data.
769
+
770
+ ### Constants
771
+
772
+ #### `paymentProvider`
773
+
774
+ PaymentProvider-compatible adapter for Stripe.
775
+
776
+ Wraps the Stripe SDK functions into a `PaymentProvider`-compatible object
777
+ for use with the molecule bond system. Supports subscription verification,
778
+ webhook handling, plan upgrades/downgrades, and cancellation.
779
+
780
+ ```typescript
781
+ const paymentProvider: PaymentProviderInterface
782
+ ```
783
+
784
+ #### `stripeSecretDefinitions`
785
+
786
+ Secret definitions required by the Stripe payments bond.
787
+
788
+ ```typescript
789
+ const stripeSecretDefinitions: SecretDefinition[]
790
+ ```
791
+
792
+ ## Core Interface
793
+
794
+ Implements `@molecule/api-payments` interface.
795
+
796
+ ## Bond Wiring
797
+
798
+ Setup function to register this provider with the bond system:
799
+
800
+ ```typescript
801
+ import { bond } from '@molecule/api-bond'
802
+ import { paymentProvider } from '@molecule/api-payments-stripe'
803
+
804
+ export function setupPaymentsStripe(): void {
805
+ bond('payments', 'stripe', paymentProvider)
806
+ }
807
+ ```
808
+
809
+ ## Injection Notes
810
+
811
+ ### Requirements
812
+
813
+ Peer dependencies:
814
+
815
+ - `@molecule/api-bond` ^1.0.1
816
+ - `@molecule/api-i18n` ^1.0.1
817
+ - `@molecule/api-payments` ^1.0.1
818
+ - `@molecule/api-jwt` ^1.0.1
819
+ - `@molecule/api-secrets` ^1.0.1
820
+
821
+ ### Environment Variables
822
+
823
+ - `STRIPE_SECRET_KEY` _(required)_ — Stripe secret key
824
+ - Setup: Stripe Dashboard → Developers → API keys; use the sk_test_ key in test mode, sk_live_ in production.
825
+ - Get it here: [https://dashboard.stripe.com/apikeys](https://dashboard.stripe.com/apikeys)
826
+ - Example: `sk_test_...`
827
+ - `STRIPE_WEBHOOK_SECRET` _(required)_ — Stripe webhook signing secret
828
+ - Setup: Stripe Dashboard → Developers → Webhooks → Add endpoint pointing at {apiUrl}/api/users/payment-notification/stripe, then copy its signing secret.
829
+ - Get it here: [https://dashboard.stripe.com/webhooks](https://dashboard.stripe.com/webhooks)
830
+ - Example: `whsec_...`
831
+
832
+ ### Runtime Dependencies
833
+
834
+ - `@molecule/api-bond`
835
+ - `@molecule/api-i18n`
836
+ - `@molecule/api-jwt`
837
+ - `@molecule/api-payments`
838
+ - `@molecule/api-secrets`
839
+ - `stripe`
840
+
841
+ Bond this as the payments provider so `@molecule/api-payments`'s `verifySubscription` (and
842
+ the payment resource) work server-side — don't call the Stripe SDK directly for
843
+ verification. Env: `STRIPE_SECRET_KEY` + `STRIPE_WEBHOOK_SECRET` are SERVER-ONLY; only the
844
+ publishable key (`pk_…`) is client-side.
845
+
846
+ **You do NOT need molecule's Express app, the `bond()` wiring, or the UI packages to use
847
+ this — the functions below are framework-agnostic.** On a non-Express / non-molecule host
848
+ (Next.js App Router, serverless functions, Hono, Fastify), import them and call them from
849
+ your OWN route handlers:
850
+ `import { createCheckoutSession, verifyWebhookSignature, getSubscription } from '@molecule/api-payments-stripe'`.
851
+ They cover the whole flow — {@link createCheckoutSession} (server-owned `priceId`, so you
852
+ never take a price/amount from the client), {@link createPortalSession} (hosted Billing
853
+ Portal for payment-method updates/cancellation/invoices), {@link verifyWebhookSignature},
854
+ and the subscription getters/updaters — and carry the security contract (config-not-configured
855
+ errors, normalized status) for free, so reach for these instead of hand-rolling raw
856
+ `stripe` calls. In a Next.js App Router route, read the RAW webhook body with
857
+ `await req.text()` and the header with `req.headers.get('stripe-signature')`, then
858
+ `verifyWebhookSignature(rawBody, signature)` (the `express.raw(...)` note below is the
859
+ Express-host equivalent). Only `@molecule/api-middleware-billing-routes` (Express glue) and
860
+ `@molecule/app-billing-react` (molecule UI) are framework-coupled — skip THOSE on such a
861
+ host, but still use these bond functions underneath.
862
+
863
+ Two things a weak Stripe integration gets wrong:
864
+
865
+ - **The webhook body MUST be RAW for signature verification.** {@link verifyWebhookSignature}
866
+ (Stripe's `constructEvent`) hashes the exact bytes, so a parsed-then-re-serialized body
867
+ ALWAYS fails. In a molecule app you need NO special middleware: the always-included
868
+ `@molecule/api-middleware-body-parser-express` already captures the unparsed body as
869
+ `req.rawBody` (a string) on EVERY request — just pass `req.rawBody` + the `stripe-signature`
870
+ header to {@link verifyWebhookSignature}. Do NOT add a route-specific `express.raw(...)` here —
871
+ it is redundant and fights the global JSON parser (which has already consumed the stream and
872
+ set `req.rawBody`). (ONLY on a NON-molecule Express host that lacks `req.rawBody` do you mount
873
+ `express.raw({ type: 'application/json' })` before the JSON parser; on Next.js App Router read
874
+ the raw body with `await req.text()`.) NEVER act on an unverified webhook body — it is
875
+ attacker-controlled.
876
+ - **Webhooks are redelivered — be idempotent.** Stripe retries until it gets a 2xx, so the
877
+ same `event.id` can arrive twice. Dedupe on it (the payment record's
878
+ `UNIQUE(platformKey, transactionId)` already blocks a double-grant), and return 2xx once
879
+ handled so Stripe stops retrying.
880
+
881
+ Create checkout with SERVER-configured price ids ({@link createCheckoutSession}) — never an
882
+ amount sent by the client.
883
+
884
+ **A missing `STRIPE_SECRET_KEY` is NOT the same as "no active subscription."**
885
+ `getClient()` throws a tagged config-not-configured error; `verifySubscription`,
886
+ `updateSubscription`, and `cancelSubscription` on {@link paymentProvider} detect
887
+ that tag (`isConfigNotConfiguredError` from `@molecule/api-payments`) and
888
+ RETHROW it instead of swallowing it into the same `null` / `{ updated: false }`
889
+ / `false` a genuine verification/update failure returns — so a caller (or its
890
+ own catch block) can tell "the operator forgot to set the secret" apart from
891
+ "this subscription/card is invalid" and surface the actionable 503 instead of
892
+ a generic 400/500.
893
+
894
+ ## E2E Tests
895
+
896
+ Integration checklist — drive the real UI (live preview, no mocks; use the
897
+ provider's TEST mode — test cards/sandbox accounts, never a live charge),
898
+ adapt each item to this app's actual screens/flows, and check every box off
899
+ one by one. A box you can't check is an integration bug to fix — not a skip:
900
+
901
+ - [ ] Starting an upgrade/subscribe from the pricing or billing surface creates a
902
+ checkout session and hands off to the provider flow (redirect or embedded
903
+ element) — the button does something real, not a dead click.
904
+ - [ ] Returning from a canceled/abandoned checkout leaves the user on their
905
+ original plan with a sane UI (no phantom entitlement, no error page).
906
+ - [ ] Entitlement flips ONLY after server-side verification (webhook or verify
907
+ call) — reloading after a client-side-only "success" must NOT show a paid
908
+ plan unless the server verified it. The sandbox CAPTURES webhook deliveries
909
+ — read them with the `read_activity` tool (filter type 'webhook'); never
910
+ mock the event or modify production code to fake an entitlement.
911
+ - [ ] The current subscription status (plan name, renewal/expiry) renders on the
912
+ account/billing screen, and canceling updates that status visibly.
913
+ - [ ] With payment secrets unconfigured, the flow surfaces an actionable
914
+ "credentials not configured" message — not a silent no-op or generic 500.
915
+ - [ ] The provider SECRET key never reaches the browser (page + network traffic
916
+ contain only the publishable key).
917
+
918
+ ## Translations
919
+
920
+ Translation strings are provided by `@molecule/api-locales-payments-stripe`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-payments-stripe",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Stripe payment provider for molecule.dev.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,8 @@
17
17
  }
18
18
  },
19
19
  "files": [
20
- "dist"
20
+ "dist",
21
+ "README.md"
21
22
  ],
22
23
  "keywords": [
23
24
  "molecule",
@@ -34,11 +35,11 @@
34
35
  "vitest": "4.1.10"
35
36
  },
36
37
  "peerDependencies": {
37
- "@molecule/api-bond": "^1.0.0",
38
- "@molecule/api-i18n": "^1.0.0",
39
- "@molecule/api-payments": "^1.0.0",
40
- "@molecule/api-jwt": "^1.0.0",
41
- "@molecule/api-secrets": "^1.0.0"
38
+ "@molecule/api-bond": "^1.0.1",
39
+ "@molecule/api-i18n": "^1.0.1",
40
+ "@molecule/api-payments": "^1.0.1",
41
+ "@molecule/api-jwt": "^1.0.1",
42
+ "@molecule/api-secrets": "^1.0.1"
42
43
  },
43
44
  "peerDependenciesMeta": {
44
45
  "@molecule/api-payments": {