chub-dev 0.1.0 → 0.1.2-beta.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.
Files changed (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1726 @@
1
+ ---
2
+ name: payments
3
+ description: "Payment processing platform with comprehensive payment and billing features including Payment Intents, Subscriptions, Checkout, customer management, webhooks, and Connect for marketplaces"
4
+ metadata:
5
+ languages: "javascript"
6
+ versions: "19.1.0"
7
+ updated-on: "2025-10-28"
8
+ source: maintainer
9
+ tags: "stripe,api,payments,billing"
10
+ ---
11
+ # Stripe API Coding Guide
12
+
13
+ ## 1. Golden Rule
14
+
15
+ **Always use the official Stripe SDK packages:**
16
+ - Server-side: `stripe` (Node.js library for Stripe API)
17
+ - Client-side: `@stripe/stripe-js` (ES module for browser)
18
+ - React: `@stripe/react-stripe-js` (React components and hooks)
19
+
20
+ **Never use deprecated or unofficial libraries.** These are the only supported Stripe packages maintained by Stripe, Inc.
21
+
22
+ **Current SDK Version:** v19.1.0 (Node.js server library)
23
+
24
+ **API Version:** Stripe uses date-based API versioning (e.g., 2025-02-24). Your account is automatically pinned to the API version from your first request. You can override this per-request or upgrade in the Stripe Dashboard.
25
+
26
+ ## 2. Installation
27
+
28
+ ### Server-Side (Node.js)
29
+
30
+ ```bash
31
+ npm install stripe
32
+ ```
33
+
34
+ ```bash
35
+ yarn add stripe
36
+ ```
37
+
38
+ ```bash
39
+ pnpm add stripe
40
+ ```
41
+
42
+ **Requirements:** Node.js 16+ (support for Node 16 is deprecated; use Node 18+ for production)
43
+
44
+ ### Client-Side (Browser)
45
+
46
+ ```bash
47
+ npm install @stripe/stripe-js
48
+ ```
49
+
50
+ ```bash
51
+ yarn add @stripe/stripe-js
52
+ ```
53
+
54
+ ### React Applications
55
+
56
+ ```bash
57
+ npm install @stripe/stripe-js @stripe/react-stripe-js
58
+ ```
59
+
60
+ ```bash
61
+ yarn add @stripe/stripe-js @stripe/react-stripe-js
62
+ ```
63
+
64
+ ### Environment Variables
65
+
66
+ ```bash
67
+ # Required
68
+ STRIPE_SECRET_KEY=sk_test_51H... # Server-side only, NEVER expose in browser
69
+ STRIPE_PUBLISHABLE_KEY=pk_test_51H... # Safe for client-side use
70
+
71
+ # Optional
72
+ STRIPE_WEBHOOK_SECRET=whsec_... # For webhook signature verification
73
+ STRIPE_API_VERSION=2025-02-24 # Override default API version
74
+ ```
75
+
76
+ **CRITICAL:** Never commit secret keys to version control. Use environment variables or secure secret management systems.
77
+
78
+ ## 3. Initialization
79
+
80
+ ### Server-Side Initialization (Node.js)
81
+
82
+ ```javascript
83
+ const Stripe = require('stripe');
84
+ const stripe = Stripe(process.env.STRIPE_SECRET_KEY);
85
+ ```
86
+
87
+ **With TypeScript:**
88
+
89
+ ```typescript
90
+ import Stripe from 'stripe';
91
+
92
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
93
+ apiVersion: '2025-02-24',
94
+ });
95
+ ```
96
+
97
+ **Advanced Configuration:**
98
+
99
+ ```javascript
100
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
101
+ apiVersion: '2025-02-24',
102
+ maxNetworkRetries: 2,
103
+ timeout: 80000, // 80 seconds
104
+ telemetry: true,
105
+ appInfo: {
106
+ name: 'MyApp',
107
+ version: '1.0.0',
108
+ url: 'https://myapp.com',
109
+ },
110
+ });
111
+ ```
112
+
113
+ ### Client-Side Initialization (Browser)
114
+
115
+ ```javascript
116
+ import { loadStripe } from '@stripe/stripe-js';
117
+
118
+ // Load Stripe.js asynchronously
119
+ const stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY);
120
+
121
+ // Later, when you need to use it
122
+ const stripe = await stripePromise;
123
+ ```
124
+
125
+ **Advanced Loading Options:**
126
+
127
+ ```javascript
128
+ const stripePromise = loadStripe(
129
+ process.env.STRIPE_PUBLISHABLE_KEY,
130
+ {
131
+ locale: 'en',
132
+ betas: ['some_beta_feature'],
133
+ apiVersion: '2025-02-24',
134
+ }
135
+ );
136
+ ```
137
+
138
+ ### React Initialization
139
+
140
+ ```javascript
141
+ import { Elements } from '@stripe/react-stripe-js';
142
+ import { loadStripe } from '@stripe/stripe-js';
143
+
144
+ const stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY);
145
+
146
+ function App() {
147
+ return (
148
+ <Elements stripe={stripePromise}>
149
+ {/* Your payment components here */}
150
+ </Elements>
151
+ );
152
+ }
153
+ ```
154
+
155
+ **With Options:**
156
+
157
+ ```javascript
158
+ function App() {
159
+ const options = {
160
+ mode: 'payment',
161
+ amount: 1099,
162
+ currency: 'usd',
163
+ appearance: {
164
+ theme: 'stripe',
165
+ variables: {
166
+ colorPrimary: '#0570de',
167
+ },
168
+ },
169
+ };
170
+
171
+ return (
172
+ <Elements stripe={stripePromise} options={options}>
173
+ <CheckoutForm />
174
+ </Elements>
175
+ );
176
+ }
177
+ ```
178
+
179
+ ## 4. Core API Surfaces
180
+
181
+ ### Payment Intents
182
+
183
+ Payment Intents are the recommended way to handle payments. They track the entire payment lifecycle and support Strong Customer Authentication (SCA).
184
+
185
+ **Minimal Server-Side Example:**
186
+
187
+ ```javascript
188
+ const paymentIntent = await stripe.paymentIntents.create({
189
+ amount: 1099, // Amount in cents ($10.99)
190
+ currency: 'usd',
191
+ payment_method_types: ['card'],
192
+ });
193
+
194
+ // Send clientSecret to client
195
+ res.json({ clientSecret: paymentIntent.client_secret });
196
+ ```
197
+
198
+ **Advanced Server-Side Example:**
199
+
200
+ ```javascript
201
+ const paymentIntent = await stripe.paymentIntents.create({
202
+ amount: 2000,
203
+ currency: 'usd',
204
+ payment_method_types: ['card', 'us_bank_account'],
205
+ customer: 'cus_123456789',
206
+ description: 'Software subscription',
207
+ metadata: {
208
+ order_id: '6735',
209
+ customer_email: 'customer@example.com',
210
+ },
211
+ statement_descriptor: 'MYCOMPANY SUB',
212
+ receipt_email: 'customer@example.com',
213
+ automatic_payment_methods: {
214
+ enabled: true,
215
+ allow_redirects: 'never',
216
+ },
217
+ capture_method: 'manual', // For later capture
218
+ });
219
+ ```
220
+
221
+ **Client-Side Confirmation (React):**
222
+
223
+ ```javascript
224
+ import { PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';
225
+
226
+ function CheckoutForm({ clientSecret }) {
227
+ const stripe = useStripe();
228
+ const elements = useElements();
229
+
230
+ const handleSubmit = async (event) => {
231
+ event.preventDefault();
232
+
233
+ if (!stripe || !elements) {
234
+ return;
235
+ }
236
+
237
+ const { error, paymentIntent } = await stripe.confirmPayment({
238
+ elements,
239
+ confirmParams: {
240
+ return_url: 'https://example.com/order/complete',
241
+ },
242
+ redirect: 'if_required',
243
+ });
244
+
245
+ if (error) {
246
+ console.error(error.message);
247
+ } else if (paymentIntent.status === 'succeeded') {
248
+ console.log('Payment successful!');
249
+ }
250
+ };
251
+
252
+ return (
253
+ <form onSubmit={handleSubmit}>
254
+ <PaymentElement />
255
+ <button disabled={!stripe}>Submit</button>
256
+ </form>
257
+ );
258
+ }
259
+ ```
260
+
261
+ **Vanilla JavaScript Confirmation:**
262
+
263
+ ```javascript
264
+ const stripe = await stripePromise;
265
+
266
+ const { error, paymentIntent } = await stripe.confirmCardPayment(
267
+ clientSecret,
268
+ {
269
+ payment_method: {
270
+ card: cardElement,
271
+ billing_details: {
272
+ name: 'John Doe',
273
+ email: 'john@example.com',
274
+ },
275
+ },
276
+ }
277
+ );
278
+
279
+ if (error) {
280
+ console.error(error.message);
281
+ } else if (paymentIntent.status === 'succeeded') {
282
+ console.log('Payment successful!');
283
+ }
284
+ ```
285
+
286
+ ### Checkout Sessions
287
+
288
+ Stripe Checkout provides a pre-built, hosted payment page.
289
+
290
+ **Minimal Server-Side Example:**
291
+
292
+ ```javascript
293
+ const session = await stripe.checkout.sessions.create({
294
+ line_items: [
295
+ {
296
+ price_data: {
297
+ currency: 'usd',
298
+ product_data: {
299
+ name: 'T-shirt',
300
+ },
301
+ unit_amount: 2000,
302
+ },
303
+ quantity: 1,
304
+ },
305
+ ],
306
+ mode: 'payment',
307
+ success_url: 'https://example.com/success',
308
+ cancel_url: 'https://example.com/cancel',
309
+ });
310
+
311
+ // Redirect to Checkout
312
+ res.redirect(303, session.url);
313
+ ```
314
+
315
+ **Advanced Server-Side Example:**
316
+
317
+ ```javascript
318
+ const session = await stripe.checkout.sessions.create({
319
+ line_items: [
320
+ {
321
+ price: 'price_1234567890', // Existing price ID
322
+ quantity: 2,
323
+ },
324
+ ],
325
+ mode: 'payment',
326
+ customer: 'cus_123456789',
327
+ customer_email: 'customer@example.com',
328
+ client_reference_id: 'order_12345',
329
+ success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
330
+ cancel_url: 'https://example.com/cancel',
331
+ automatic_tax: { enabled: true },
332
+ allow_promotion_codes: true,
333
+ billing_address_collection: 'required',
334
+ shipping_address_collection: {
335
+ allowed_countries: ['US', 'CA'],
336
+ },
337
+ payment_method_types: ['card', 'us_bank_account'],
338
+ metadata: {
339
+ order_id: '6735',
340
+ },
341
+ invoice_creation: {
342
+ enabled: true,
343
+ },
344
+ });
345
+ ```
346
+
347
+ **Client-Side Redirect:**
348
+
349
+ ```javascript
350
+ import { loadStripe } from '@stripe/stripe-js';
351
+
352
+ const stripe = await loadStripe(publishableKey);
353
+
354
+ // Redirect to Checkout
355
+ const { error } = await stripe.redirectToCheckout({
356
+ sessionId: session.id,
357
+ });
358
+
359
+ if (error) {
360
+ console.error(error.message);
361
+ }
362
+ ```
363
+
364
+ ### Customers
365
+
366
+ Customers represent your users in Stripe.
367
+
368
+ **Minimal Example:**
369
+
370
+ ```javascript
371
+ const customer = await stripe.customers.create({
372
+ email: 'customer@example.com',
373
+ });
374
+ ```
375
+
376
+ **Advanced Example:**
377
+
378
+
379
+ ```javascript
380
+ const customer = await stripe.customers.create({
381
+ email: 'customer@example.com',
382
+ name: 'John Doe',
383
+ phone: '+15555551234',
384
+ description: 'Premium customer',
385
+ metadata: {
386
+ user_id: 'user_12345',
387
+ plan: 'premium',
388
+ },
389
+ address: {
390
+ line1: '510 Townsend St',
391
+ city: 'San Francisco',
392
+ state: 'CA',
393
+ postal_code: '94103',
394
+ country: 'US',
395
+ },
396
+ payment_method: 'pm_card_visa',
397
+ invoice_settings: {
398
+ default_payment_method: 'pm_card_visa',
399
+ },
400
+ });
401
+ ```
402
+
403
+ **Retrieve and Update:**
404
+
405
+ ```javascript
406
+ // Retrieve customer
407
+ const customer = await stripe.customers.retrieve('cus_123456789');
408
+
409
+ // Update customer
410
+ const updatedCustomer = await stripe.customers.update('cus_123456789', {
411
+ metadata: { vip: 'true' },
412
+ email: 'newemail@example.com',
413
+ });
414
+
415
+ // List customers
416
+ const customers = await stripe.customers.list({
417
+ limit: 100,
418
+ email: 'customer@example.com',
419
+ });
420
+ ```
421
+
422
+ **Attach Payment Method to Customer:**
423
+
424
+ ```javascript
425
+ const paymentMethod = await stripe.paymentMethods.attach(
426
+ 'pm_card_visa',
427
+ { customer: 'cus_123456789' }
428
+ );
429
+
430
+ // Set as default payment method
431
+ await stripe.customers.update('cus_123456789', {
432
+ invoice_settings: {
433
+ default_payment_method: 'pm_card_visa',
434
+ },
435
+ });
436
+ ```
437
+
438
+ ### Subscriptions
439
+
440
+ Subscriptions bill customers on a recurring basis.
441
+
442
+ **Minimal Example:**
443
+
444
+ ```javascript
445
+ const subscription = await stripe.subscriptions.create({
446
+ customer: 'cus_123456789',
447
+ items: [
448
+ { price: 'price_1234567890' },
449
+ ],
450
+ });
451
+ ```
452
+
453
+ **Advanced Example:**
454
+
455
+ ```javascript
456
+ const subscription = await stripe.subscriptions.create({
457
+ customer: 'cus_123456789',
458
+ items: [
459
+ {
460
+ price: 'price_1234567890',
461
+ quantity: 1,
462
+ },
463
+ ],
464
+ payment_behavior: 'default_incomplete',
465
+ payment_settings: {
466
+ payment_method_types: ['card', 'us_bank_account'],
467
+ save_default_payment_method: 'on_subscription',
468
+ },
469
+ expand: ['latest_invoice.payment_intent'],
470
+ trial_period_days: 14,
471
+ metadata: {
472
+ user_id: 'user_12345',
473
+ },
474
+ proration_behavior: 'create_prorations',
475
+ billing_cycle_anchor_config: {
476
+ day_of_month: 1,
477
+ },
478
+ automatic_tax: {
479
+ enabled: true,
480
+ },
481
+ });
482
+
483
+ // Return client secret for payment confirmation
484
+ const clientSecret = subscription.latest_invoice.payment_intent.client_secret;
485
+ ```
486
+
487
+ **Update Subscription:**
488
+
489
+ ```javascript
490
+ const updatedSubscription = await stripe.subscriptions.update(
491
+ 'sub_1234567890',
492
+ {
493
+ items: [
494
+ {
495
+ id: 'si_1234567890',
496
+ price: 'price_new_plan',
497
+ },
498
+ ],
499
+ proration_behavior: 'always_invoice',
500
+ }
501
+ );
502
+ ```
503
+
504
+ **Cancel Subscription:**
505
+
506
+ ```javascript
507
+ // Cancel at period end
508
+ const subscription = await stripe.subscriptions.update('sub_1234567890', {
509
+ cancel_at_period_end: true,
510
+ });
511
+
512
+ // Cancel immediately
513
+ const canceledSubscription = await stripe.subscriptions.cancel('sub_1234567890');
514
+ ```
515
+
516
+ ### Products and Prices
517
+
518
+ Products represent what you sell, Prices define how you charge for products.
519
+
520
+ **Create Product:**
521
+
522
+ ```javascript
523
+ const product = await stripe.products.create({
524
+ name: 'Premium Subscription',
525
+ description: 'Access to all premium features',
526
+ metadata: {
527
+ category: 'subscription',
528
+ },
529
+ });
530
+ ```
531
+
532
+ **Create Price (One-Time):**
533
+
534
+ ```javascript
535
+ const price = await stripe.prices.create({
536
+ product: 'prod_1234567890',
537
+ unit_amount: 2000,
538
+ currency: 'usd',
539
+ });
540
+ ```
541
+
542
+ **Create Price (Recurring):**
543
+
544
+ ```javascript
545
+ const recurringPrice = await stripe.prices.create({
546
+ product: 'prod_1234567890',
547
+ unit_amount: 1500,
548
+ currency: 'usd',
549
+ recurring: {
550
+ interval: 'month',
551
+ interval_count: 1,
552
+ usage_type: 'licensed',
553
+ },
554
+ billing_scheme: 'per_unit',
555
+ tax_behavior: 'exclusive',
556
+ });
557
+ ```
558
+
559
+ **Advanced Pricing (Tiered):**
560
+
561
+ ```javascript
562
+ const tieredPrice = await stripe.prices.create({
563
+ product: 'prod_1234567890',
564
+ currency: 'usd',
565
+ recurring: {
566
+ interval: 'month',
567
+ usage_type: 'metered',
568
+ },
569
+ billing_scheme: 'tiered',
570
+ tiers_mode: 'graduated',
571
+ tiers: [
572
+ {
573
+ up_to: 10,
574
+ unit_amount: 1000,
575
+ },
576
+ {
577
+ up_to: 100,
578
+ unit_amount: 800,
579
+ },
580
+ {
581
+ up_to: 'inf',
582
+ unit_amount: 500,
583
+ },
584
+ ],
585
+ });
586
+ ```
587
+
588
+ ### Payment Methods
589
+
590
+ Payment Methods represent customer payment details.
591
+
592
+ **Create Payment Method (Server-Side):**
593
+
594
+ ```javascript
595
+ const paymentMethod = await stripe.paymentMethods.create({
596
+ type: 'card',
597
+ card: {
598
+ token: 'tok_visa',
599
+ },
600
+ });
601
+ ```
602
+
603
+ **Create Payment Method (Client-Side with Elements):**
604
+
605
+ ```javascript
606
+ const stripe = await stripePromise;
607
+ const elements = stripe.elements();
608
+ const cardElement = elements.create('card');
609
+ cardElement.mount('#card-element');
610
+
611
+ // When form is submitted
612
+ const { error, paymentMethod } = await stripe.createPaymentMethod({
613
+ type: 'card',
614
+ card: cardElement,
615
+ billing_details: {
616
+ name: 'John Doe',
617
+ email: 'john@example.com',
618
+ },
619
+ });
620
+
621
+ if (error) {
622
+ console.error(error.message);
623
+ } else {
624
+ console.log('PaymentMethod created:', paymentMethod.id);
625
+ }
626
+ ```
627
+
628
+ **List Customer Payment Methods:**
629
+
630
+ ```javascript
631
+ const paymentMethods = await stripe.paymentMethods.list({
632
+ customer: 'cus_123456789',
633
+ type: 'card',
634
+ });
635
+ ```
636
+
637
+ **Detach Payment Method:**
638
+
639
+ ```javascript
640
+ const detachedPM = await stripe.paymentMethods.detach('pm_1234567890');
641
+ ```
642
+
643
+ ### Refunds
644
+
645
+ **Create Refund:**
646
+
647
+ ```javascript
648
+ // Full refund
649
+ const refund = await stripe.refunds.create({
650
+ payment_intent: 'pi_1234567890',
651
+ });
652
+
653
+ // Partial refund
654
+ const partialRefund = await stripe.refunds.create({
655
+ payment_intent: 'pi_1234567890',
656
+ amount: 500, // Refund $5.00 of original charge
657
+ reason: 'requested_by_customer',
658
+ metadata: {
659
+ reason_detail: 'Customer changed mind',
660
+ },
661
+ });
662
+ ```
663
+
664
+ **Retrieve Refund:**
665
+
666
+ ```javascript
667
+ const refund = await stripe.refunds.retrieve('re_1234567890');
668
+ ```
669
+
670
+ ### Webhooks
671
+
672
+ Webhooks notify your application when events occur in your Stripe account.
673
+
674
+ **Setup Webhook Endpoint (Express.js):**
675
+
676
+ ```javascript
677
+ const express = require('express');
678
+ const app = express();
679
+
680
+ // CRITICAL: Use raw body for webhook signature verification
681
+ app.post(
682
+ '/webhook',
683
+ express.raw({ type: 'application/json' }),
684
+ async (req, res) => {
685
+ const sig = req.headers['stripe-signature'];
686
+ const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
687
+
688
+ let event;
689
+
690
+ try {
691
+ event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
692
+ } catch (err) {
693
+ console.error(`Webhook signature verification failed: ${err.message}`);
694
+ return res.status(400).send(`Webhook Error: ${err.message}`);
695
+ }
696
+
697
+ // Handle the event
698
+ switch (event.type) {
699
+ case 'payment_intent.succeeded':
700
+ const paymentIntent = event.data.object;
701
+ console.log('PaymentIntent succeeded:', paymentIntent.id);
702
+ // Fulfill the order
703
+ break;
704
+ case 'payment_intent.payment_failed':
705
+ const failedPayment = event.data.object;
706
+ console.log('Payment failed:', failedPayment.id);
707
+ // Notify customer
708
+ break;
709
+ case 'customer.subscription.created':
710
+ const subscription = event.data.object;
711
+ console.log('Subscription created:', subscription.id);
712
+ break;
713
+ case 'customer.subscription.updated':
714
+ const updatedSub = event.data.object;
715
+ console.log('Subscription updated:', updatedSub.id);
716
+ break;
717
+ case 'customer.subscription.deleted':
718
+ const canceledSub = event.data.object;
719
+ console.log('Subscription canceled:', canceledSub.id);
720
+ break;
721
+ default:
722
+ console.log(`Unhandled event type ${event.type}`);
723
+ }
724
+
725
+ res.json({ received: true });
726
+ }
727
+ );
728
+ ```
729
+
730
+ **Advanced Webhook Handling:**
731
+
732
+ ```javascript
733
+ app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
734
+ const sig = req.headers['stripe-signature'];
735
+ const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
736
+
737
+ let event;
738
+
739
+ try {
740
+ event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
741
+ } catch (err) {
742
+ console.error(`Webhook Error: ${err.message}`);
743
+ return res.status(400).send(`Webhook Error: ${err.message}`);
744
+ }
745
+
746
+ // Handle event asynchronously to respond quickly
747
+ processWebhookEvent(event)
748
+ .then(() => console.log('Event processed successfully'))
749
+ .catch((err) => console.error('Event processing failed:', err));
750
+
751
+ // Respond immediately
752
+ res.json({ received: true });
753
+ });
754
+
755
+ async function processWebhookEvent(event) {
756
+ const eventData = event.data.object;
757
+
758
+ switch (event.type) {
759
+ case 'checkout.session.completed':
760
+ const session = eventData;
761
+ // Fulfill order based on session
762
+ if (session.mode === 'payment') {
763
+ await fulfillOrder(session);
764
+ } else if (session.mode === 'subscription') {
765
+ await activateSubscription(session);
766
+ }
767
+ break;
768
+
769
+ case 'invoice.paid':
770
+ // Handle successful payment of invoice
771
+ await handleInvoicePaid(eventData);
772
+ break;
773
+
774
+ case 'invoice.payment_failed':
775
+ // Handle failed payment
776
+ await notifyCustomerPaymentFailed(eventData);
777
+ break;
778
+
779
+ default:
780
+ console.log(`Unhandled event type: ${event.type}`);
781
+ }
782
+ }
783
+ ```
784
+
785
+ ### Invoices
786
+
787
+ **Create Invoice:**
788
+
789
+ ```javascript
790
+ // Create invoice item
791
+ await stripe.invoiceItems.create({
792
+ customer: 'cus_123456789',
793
+ amount: 2500,
794
+ currency: 'usd',
795
+ description: 'One-time setup fee',
796
+ });
797
+
798
+ // Create and finalize invoice
799
+ const invoice = await stripe.invoices.create({
800
+ customer: 'cus_123456789',
801
+ auto_advance: true, // Auto-finalize
802
+ collection_method: 'charge_automatically',
803
+ });
804
+
805
+ // Finalize invoice (if not auto-advance)
806
+ const finalizedInvoice = await stripe.invoices.finalizeInvoice(invoice.id);
807
+
808
+ // Pay invoice
809
+ const paidInvoice = await stripe.invoices.pay(invoice.id);
810
+ ```
811
+
812
+ ### Customer Portal
813
+
814
+ The Customer Portal allows customers to manage their subscription and billing information.
815
+
816
+ **Create Portal Session:**
817
+
818
+ ```javascript
819
+ const portalSession = await stripe.billingPortal.sessions.create({
820
+ customer: 'cus_123456789',
821
+ return_url: 'https://example.com/account',
822
+ });
823
+
824
+ // Redirect customer to portal
825
+ res.redirect(303, portalSession.url);
826
+ ```
827
+
828
+ **Advanced Portal Configuration:**
829
+
830
+ ```javascript
831
+ // Create a portal configuration
832
+ const configuration = await stripe.billingPortal.configurations.create({
833
+ business_profile: {
834
+ headline: 'Manage your subscription',
835
+ },
836
+ features: {
837
+ customer_update: {
838
+ enabled: true,
839
+ allowed_updates: ['email', 'address', 'shipping', 'phone', 'tax_id'],
840
+ },
841
+ invoice_history: {
842
+ enabled: true,
843
+ },
844
+ payment_method_update: {
845
+ enabled: true,
846
+ },
847
+ subscription_cancel: {
848
+ enabled: true,
849
+ mode: 'at_period_end',
850
+ cancellation_reason: {
851
+ enabled: true,
852
+ options: [
853
+ 'too_expensive',
854
+ 'missing_features',
855
+ 'switched_service',
856
+ 'unused',
857
+ 'other',
858
+ ],
859
+ },
860
+ },
861
+ subscription_update: {
862
+ enabled: true,
863
+ default_allowed_updates: ['price', 'quantity', 'promotion_code'],
864
+ proration_behavior: 'always_invoice',
865
+ products: [
866
+ {
867
+ product: 'prod_basic',
868
+ prices: ['price_basic_monthly', 'price_basic_yearly'],
869
+ },
870
+ {
871
+ product: 'prod_premium',
872
+ prices: ['price_premium_monthly', 'price_premium_yearly'],
873
+ },
874
+ ],
875
+ },
876
+ },
877
+ });
878
+
879
+ // Use custom configuration
880
+ const portalSession = await stripe.billingPortal.sessions.create({
881
+ customer: 'cus_123456789',
882
+ return_url: 'https://example.com/account',
883
+ configuration: configuration.id,
884
+ });
885
+ ```
886
+
887
+ ### Charges (Legacy - Use Payment Intents Instead)
888
+
889
+ **Note:** Charges API is legacy. Use Payment Intents for new integrations.
890
+
891
+ ```javascript
892
+ // Only use if you have a specific reason not to use Payment Intents
893
+ const charge = await stripe.charges.create({
894
+ amount: 2000,
895
+ currency: 'usd',
896
+ source: 'tok_visa',
897
+ description: 'Legacy charge',
898
+ });
899
+ ```
900
+
901
+ ## 5. Best Practices
902
+
903
+ ### Idempotency
904
+
905
+ Stripe supports idempotency to safely retry requests without performing the same operation twice.
906
+
907
+ ```javascript
908
+ // Generate unique idempotency key
909
+ const { v4: uuidv4 } = require('uuid');
910
+
911
+ const paymentIntent = await stripe.paymentIntents.create(
912
+ {
913
+ amount: 1000,
914
+ currency: 'usd',
915
+ },
916
+ {
917
+ idempotencyKey: uuidv4(), // Unique key per request
918
+ }
919
+ );
920
+ ```
921
+
922
+ **Automatic Retries with Idempotency:**
923
+
924
+ ```javascript
925
+ async function createPaymentWithRetry(paymentData, maxRetries = 3) {
926
+ const idempotencyKey = uuidv4();
927
+
928
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
929
+ try {
930
+ const paymentIntent = await stripe.paymentIntents.create(
931
+ paymentData,
932
+ { idempotencyKey }
933
+ );
934
+ return paymentIntent;
935
+ } catch (err) {
936
+ if (attempt === maxRetries) throw err;
937
+
938
+ // Only retry on network errors or rate limits
939
+ if (err.type === 'StripeConnectionError' || err.statusCode === 429) {
940
+ const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
941
+ await new Promise(resolve => setTimeout(resolve, delay));
942
+ } else {
943
+ throw err; // Don't retry on other errors
944
+ }
945
+ }
946
+ }
947
+ }
948
+ ```
949
+
950
+ ### Error Handling
951
+
952
+ Stripe errors include specific types for targeted handling.
953
+
954
+ ```javascript
955
+ async function handleStripeOperation() {
956
+ try {
957
+ const paymentIntent = await stripe.paymentIntents.create({
958
+ amount: 1000,
959
+ currency: 'usd',
960
+ });
961
+ return paymentIntent;
962
+ } catch (err) {
963
+ switch (err.type) {
964
+ case 'StripeCardError':
965
+ // Card was declined
966
+ console.error('Card declined:', err.message);
967
+ return { error: 'Your card was declined.' };
968
+
969
+ case 'StripeRateLimitError':
970
+ // Too many requests
971
+ console.error('Rate limit hit');
972
+ return { error: 'Too many requests. Please try again later.' };
973
+
974
+ case 'StripeInvalidRequestError':
975
+ // Invalid parameters
976
+ console.error('Invalid request:', err.message);
977
+ return { error: 'Invalid payment information.' };
978
+
979
+ case 'StripeAPIError':
980
+ // Stripe API error
981
+ console.error('API error:', err.message);
982
+ return { error: 'Payment processing error. Please try again.' };
983
+
984
+ case 'StripeConnectionError':
985
+ // Network error
986
+ console.error('Network error:', err.message);
987
+ return { error: 'Network error. Please check your connection.' };
988
+
989
+ case 'StripeAuthenticationError':
990
+ // Authentication error
991
+ console.error('Authentication failed:', err.message);
992
+ return { error: 'Payment system error.' };
993
+
994
+ default:
995
+ console.error('Unknown error:', err);
996
+ return { error: 'An unexpected error occurred.' };
997
+ }
998
+ }
999
+ }
1000
+ ```
1001
+
1002
+ **Comprehensive Error Handler:**
1003
+
1004
+ ```javascript
1005
+ class StripeErrorHandler {
1006
+ static async execute(operation, options = {}) {
1007
+ const { maxRetries = 3, retryDelay = 1000 } = options;
1008
+
1009
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1010
+ try {
1011
+ return await operation();
1012
+ } catch (err) {
1013
+ const shouldRetry = this.shouldRetry(err, attempt, maxRetries);
1014
+
1015
+ if (!shouldRetry) {
1016
+ throw this.formatError(err);
1017
+ }
1018
+
1019
+ const delay = retryDelay * Math.pow(2, attempt - 1);
1020
+ await new Promise(resolve => setTimeout(resolve, delay));
1021
+ }
1022
+ }
1023
+ }
1024
+
1025
+ static shouldRetry(err, attempt, maxRetries) {
1026
+ if (attempt >= maxRetries) return false;
1027
+
1028
+ return (
1029
+ err.type === 'StripeConnectionError' ||
1030
+ err.type === 'StripeAPIError' ||
1031
+ err.statusCode === 429 ||
1032
+ err.statusCode === 503
1033
+ );
1034
+ }
1035
+
1036
+ static formatError(err) {
1037
+ return {
1038
+ type: err.type,
1039
+ message: err.message,
1040
+ statusCode: err.statusCode,
1041
+ code: err.code,
1042
+ decline_code: err.decline_code,
1043
+ param: err.param,
1044
+ };
1045
+ }
1046
+ }
1047
+
1048
+ // Usage
1049
+ const paymentIntent = await StripeErrorHandler.execute(
1050
+ () => stripe.paymentIntents.create({ amount: 1000, currency: 'usd' }),
1051
+ { maxRetries: 3, retryDelay: 1000 }
1052
+ );
1053
+ ```
1054
+
1055
+ ### Rate Limit Handling
1056
+
1057
+ Stripe enforces rate limits to ensure API stability.
1058
+
1059
+ ```javascript
1060
+ async function rateLimitedRequest(requestFn, maxRetries = 5) {
1061
+ for (let i = 0; i < maxRetries; i++) {
1062
+ try {
1063
+ return await requestFn();
1064
+ } catch (err) {
1065
+ if (err.statusCode === 429) {
1066
+ // Rate limited - use exponential backoff
1067
+ const delay = Math.min(1000 * Math.pow(2, i), 32000);
1068
+ console.log(`Rate limited. Retrying in ${delay}ms...`);
1069
+ await new Promise(resolve => setTimeout(resolve, delay));
1070
+ } else {
1071
+ throw err;
1072
+ }
1073
+ }
1074
+ }
1075
+ throw new Error('Max retries exceeded for rate limit');
1076
+ }
1077
+
1078
+ // Usage
1079
+ const customer = await rateLimitedRequest(() =>
1080
+ stripe.customers.create({ email: 'customer@example.com' })
1081
+ );
1082
+ ```
1083
+
1084
+ **Advanced Rate Limit Strategy:**
1085
+
1086
+ ```javascript
1087
+ class RateLimiter {
1088
+ constructor(requestsPerSecond = 100) {
1089
+ this.requestsPerSecond = requestsPerSecond;
1090
+ this.queue = [];
1091
+ this.processing = false;
1092
+ }
1093
+
1094
+ async execute(fn) {
1095
+ return new Promise((resolve, reject) => {
1096
+ this.queue.push({ fn, resolve, reject });
1097
+ this.processQueue();
1098
+ });
1099
+ }
1100
+
1101
+ async processQueue() {
1102
+ if (this.processing || this.queue.length === 0) return;
1103
+
1104
+ this.processing = true;
1105
+ const { fn, resolve, reject } = this.queue.shift();
1106
+
1107
+ try {
1108
+ const result = await fn();
1109
+ resolve(result);
1110
+ } catch (err) {
1111
+ if (err.statusCode === 429) {
1112
+ // Re-queue with higher priority
1113
+ this.queue.unshift({ fn, resolve, reject });
1114
+ await new Promise(r => setTimeout(r, 2000));
1115
+ } else {
1116
+ reject(err);
1117
+ }
1118
+ } finally {
1119
+ this.processing = false;
1120
+ const delay = 1000 / this.requestsPerSecond;
1121
+ setTimeout(() => this.processQueue(), delay);
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ const limiter = new RateLimiter(100); // 100 requests per second
1127
+
1128
+ // Usage
1129
+ const customer = await limiter.execute(() =>
1130
+ stripe.customers.create({ email: 'customer@example.com' })
1131
+ );
1132
+ ```
1133
+
1134
+ ### Pagination
1135
+
1136
+ Many Stripe API methods return paginated results.
1137
+
1138
+ ```javascript
1139
+ // Manual pagination
1140
+ const customers = await stripe.customers.list({
1141
+ limit: 100,
1142
+ });
1143
+
1144
+ // Iterate through pages
1145
+ let hasMore = customers.has_more;
1146
+ let startingAfter = customers.data[customers.data.length - 1].id;
1147
+
1148
+ while (hasMore) {
1149
+ const nextPage = await stripe.customers.list({
1150
+ limit: 100,
1151
+ starting_after: startingAfter,
1152
+ });
1153
+
1154
+ customers.data.push(...nextPage.data);
1155
+ hasMore = nextPage.has_more;
1156
+
1157
+ if (hasMore) {
1158
+ startingAfter = nextPage.data[nextPage.data.length - 1].id;
1159
+ }
1160
+ }
1161
+ ```
1162
+
1163
+ **Auto-Pagination:**
1164
+
1165
+ ```javascript
1166
+ // Stripe SDK provides auto-pagination
1167
+ const allCustomers = [];
1168
+
1169
+ for await (const customer of stripe.customers.list({ limit: 100 })) {
1170
+ allCustomers.push(customer);
1171
+
1172
+ // Process customer
1173
+ console.log(customer.email);
1174
+
1175
+ // Optional: Stop after certain condition
1176
+ if (allCustomers.length >= 500) break;
1177
+ }
1178
+ ```
1179
+
1180
+ ### Testing
1181
+
1182
+ Stripe provides test mode with test API keys and test card numbers.
1183
+
1184
+ **Test Card Numbers:**
1185
+
1186
+ ```javascript
1187
+ // Use these in test mode
1188
+ const testCards = {
1189
+ visa: '4242424242424242',
1190
+ visaDebit: '4000056655665556',
1191
+ mastercard: '5555555555554444',
1192
+ amex: '378282246310005',
1193
+ discover: '6011111111111117',
1194
+ dinersClub: '3056930009020004',
1195
+ jcb: '3566002020360505',
1196
+ unionPay: '6200000000000005',
1197
+
1198
+ // Cards that trigger specific scenarios
1199
+ declined: '4000000000000002',
1200
+ insufficientFunds: '4000000000009995',
1201
+ lostCard: '4000000000009987',
1202
+ stolenCard: '4000000000009979',
1203
+ expiredCard: '4000000000000069',
1204
+ incorrectCvc: '4000000000000127',
1205
+ processingError: '4000000000000119',
1206
+
1207
+ // 3D Secure authentication required
1208
+ authRequired: '4000002500003155',
1209
+ authRequiredDeclined: '4000008400001629',
1210
+ };
1211
+ ```
1212
+
1213
+ **Test Mode Detection:**
1214
+
1215
+ ```javascript
1216
+ const isTestMode = process.env.STRIPE_SECRET_KEY.startsWith('sk_test_');
1217
+
1218
+ if (isTestMode) {
1219
+ console.log('Running in TEST mode');
1220
+ } else {
1221
+ console.log('Running in LIVE mode');
1222
+ }
1223
+ ```
1224
+
1225
+ **Mock Stripe for Unit Tests:**
1226
+
1227
+ ```javascript
1228
+ // Using jest
1229
+ jest.mock('stripe', () => {
1230
+ return jest.fn().mockImplementation(() => ({
1231
+ paymentIntents: {
1232
+ create: jest.fn().mockResolvedValue({
1233
+ id: 'pi_test_123',
1234
+ client_secret: 'pi_test_123_secret',
1235
+ status: 'requires_payment_method',
1236
+ }),
1237
+ retrieve: jest.fn().mockResolvedValue({
1238
+ id: 'pi_test_123',
1239
+ status: 'succeeded',
1240
+ }),
1241
+ },
1242
+ customers: {
1243
+ create: jest.fn().mockResolvedValue({
1244
+ id: 'cus_test_123',
1245
+ email: 'test@example.com',
1246
+ }),
1247
+ },
1248
+ }));
1249
+ });
1250
+
1251
+ // Test
1252
+ const stripe = require('stripe')();
1253
+ const paymentIntent = await stripe.paymentIntents.create({
1254
+ amount: 1000,
1255
+ currency: 'usd',
1256
+ });
1257
+ expect(paymentIntent.id).toBe('pi_test_123');
1258
+ ```
1259
+
1260
+ ### Security Best Practices
1261
+
1262
+ **1. Never Expose Secret Keys:**
1263
+
1264
+ ```javascript
1265
+ // NEVER do this
1266
+ const stripe = require('stripe')('sk_live_actual_secret_key_hardcoded');
1267
+
1268
+ // ALWAYS do this
1269
+ const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
1270
+ ```
1271
+
1272
+ **2. Validate Webhook Signatures:**
1273
+
1274
+ ```javascript
1275
+ // ALWAYS verify webhook signatures
1276
+ try {
1277
+ const event = stripe.webhooks.constructEvent(
1278
+ req.body,
1279
+ req.headers['stripe-signature'],
1280
+ process.env.STRIPE_WEBHOOK_SECRET
1281
+ );
1282
+ } catch (err) {
1283
+ // Signature verification failed - reject the request
1284
+ return res.status(400).send(`Webhook Error: ${err.message}`);
1285
+ }
1286
+ ```
1287
+
1288
+ **3. Use HTTPS in Production:**
1289
+
1290
+ ```javascript
1291
+ // Ensure your server uses HTTPS
1292
+ if (process.env.NODE_ENV === 'production' && !req.secure) {
1293
+ return res.redirect('https://' + req.headers.host + req.url);
1294
+ }
1295
+ ```
1296
+
1297
+ **4. Server-Side Validation:**
1298
+
1299
+ ```javascript
1300
+ // NEVER trust client-side data
1301
+ app.post('/create-payment-intent', async (req, res) => {
1302
+ // Don't use amount from client
1303
+ // const { amount } = req.body; // UNSAFE
1304
+
1305
+ // Calculate amount server-side based on cart/order
1306
+ const order = await getOrderFromDatabase(req.body.orderId);
1307
+ const amount = calculateOrderTotal(order);
1308
+
1309
+ const paymentIntent = await stripe.paymentIntents.create({
1310
+ amount,
1311
+ currency: 'usd',
1312
+ });
1313
+
1314
+ res.json({ clientSecret: paymentIntent.client_secret });
1315
+ });
1316
+ ```
1317
+
1318
+ **5. PCI Compliance:**
1319
+
1320
+ ```javascript
1321
+ // NEVER handle raw card data on your server
1322
+ // ALWAYS use Stripe.js or Elements to collect card information
1323
+
1324
+ // DON'T do this:
1325
+ app.post('/charge', async (req, res) => {
1326
+ const { cardNumber, cvc, expMonth, expYear } = req.body; // NEVER
1327
+ // ...
1328
+ });
1329
+
1330
+ // DO this instead:
1331
+ // Use Stripe.js on client to create PaymentMethod
1332
+ // Only send PaymentMethod ID to server
1333
+ app.post('/charge', async (req, res) => {
1334
+ const { paymentMethodId } = req.body; // Safe
1335
+ const paymentIntent = await stripe.paymentIntents.create({
1336
+ amount: 1000,
1337
+ currency: 'usd',
1338
+ payment_method: paymentMethodId,
1339
+ });
1340
+ });
1341
+ ```
1342
+
1343
+ ### Metadata Best Practices
1344
+
1345
+ Metadata helps you store additional information on Stripe objects.
1346
+
1347
+ ```javascript
1348
+ // Use metadata to link Stripe objects to your system
1349
+ const customer = await stripe.customers.create({
1350
+ email: 'customer@example.com',
1351
+ metadata: {
1352
+ user_id: '12345',
1353
+ account_type: 'premium',
1354
+ signup_date: new Date().toISOString(),
1355
+ },
1356
+ });
1357
+
1358
+ const paymentIntent = await stripe.paymentIntents.create({
1359
+ amount: 2000,
1360
+ currency: 'usd',
1361
+ metadata: {
1362
+ order_id: 'order_789',
1363
+ customer_id: '12345',
1364
+ product_ids: 'prod_1,prod_2,prod_3',
1365
+ campaign: 'summer_sale',
1366
+ },
1367
+ });
1368
+
1369
+ // Search using metadata
1370
+ const orders = await stripe.paymentIntents.search({
1371
+ query: 'metadata["order_id"]:"order_789"',
1372
+ });
1373
+ ```
1374
+
1375
+ ### Logging and Monitoring
1376
+
1377
+ ```javascript
1378
+ // Create a logging wrapper
1379
+ class StripeClient {
1380
+ constructor(apiKey) {
1381
+ this.stripe = require('stripe')(apiKey);
1382
+ this.logger = console; // Replace with your logger
1383
+ }
1384
+
1385
+ async createPaymentIntent(params) {
1386
+ const startTime = Date.now();
1387
+
1388
+ try {
1389
+ this.logger.info('Creating payment intent', { params });
1390
+
1391
+ const paymentIntent = await this.stripe.paymentIntents.create(params);
1392
+
1393
+ const duration = Date.now() - startTime;
1394
+ this.logger.info('Payment intent created', {
1395
+ id: paymentIntent.id,
1396
+ amount: paymentIntent.amount,
1397
+ duration,
1398
+ });
1399
+
1400
+ return paymentIntent;
1401
+ } catch (err) {
1402
+ const duration = Date.now() - startTime;
1403
+ this.logger.error('Payment intent creation failed', {
1404
+ error: err.message,
1405
+ type: err.type,
1406
+ code: err.code,
1407
+ duration,
1408
+ });
1409
+
1410
+ throw err;
1411
+ }
1412
+ }
1413
+ }
1414
+
1415
+ const stripeClient = new StripeClient(process.env.STRIPE_SECRET_KEY);
1416
+ ```
1417
+
1418
+ ### Production Deployment Checklist
1419
+
1420
+ **Environment Configuration:**
1421
+
1422
+ ```javascript
1423
+ // config.js
1424
+ module.exports = {
1425
+ stripe: {
1426
+ secretKey: process.env.STRIPE_SECRET_KEY,
1427
+ publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
1428
+ webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
1429
+ apiVersion: '2025-02-24',
1430
+ },
1431
+
1432
+ // Validate required environment variables
1433
+ validate: () => {
1434
+ const required = [
1435
+ 'STRIPE_SECRET_KEY',
1436
+ 'STRIPE_PUBLISHABLE_KEY',
1437
+ 'STRIPE_WEBHOOK_SECRET',
1438
+ ];
1439
+
1440
+ for (const key of required) {
1441
+ if (!process.env[key]) {
1442
+ throw new Error(`Missing required environment variable: ${key}`);
1443
+ }
1444
+ }
1445
+
1446
+ // Ensure production uses live keys
1447
+ if (process.env.NODE_ENV === 'production') {
1448
+ if (!process.env.STRIPE_SECRET_KEY.startsWith('sk_live_')) {
1449
+ throw new Error('Production must use live Stripe keys');
1450
+ }
1451
+ }
1452
+ },
1453
+ };
1454
+ ```
1455
+
1456
+ **Webhook Endpoint Security:**
1457
+
1458
+ ```javascript
1459
+ // Dedicated webhook handler with security
1460
+ app.post(
1461
+ '/webhook',
1462
+ express.raw({ type: 'application/json' }),
1463
+ rateLimitMiddleware({ max: 100, windowMs: 60000 }), // Rate limiting
1464
+ async (req, res) => {
1465
+ const sig = req.headers['stripe-signature'];
1466
+
1467
+ let event;
1468
+
1469
+ try {
1470
+ // Verify signature
1471
+ event = stripe.webhooks.constructEvent(
1472
+ req.body,
1473
+ sig,
1474
+ process.env.STRIPE_WEBHOOK_SECRET
1475
+ );
1476
+ } catch (err) {
1477
+ logger.error('Webhook signature verification failed', {
1478
+ error: err.message,
1479
+ ip: req.ip,
1480
+ });
1481
+ return res.status(400).send(`Webhook Error: ${err.message}`);
1482
+ }
1483
+
1484
+ // Log webhook received
1485
+ logger.info('Webhook received', {
1486
+ type: event.type,
1487
+ id: event.id,
1488
+ });
1489
+
1490
+ // Process asynchronously
1491
+ processWebhook(event).catch(err => {
1492
+ logger.error('Webhook processing failed', {
1493
+ type: event.type,
1494
+ id: event.id,
1495
+ error: err.message,
1496
+ });
1497
+ });
1498
+
1499
+ // Respond immediately
1500
+ res.json({ received: true });
1501
+ }
1502
+ );
1503
+ ```
1504
+
1505
+ ### Performance Optimization
1506
+
1507
+ **Parallel Requests:**
1508
+
1509
+ ```javascript
1510
+ // Execute multiple independent requests in parallel
1511
+ const [customer, product, price] = await Promise.all([
1512
+ stripe.customers.retrieve('cus_123'),
1513
+ stripe.products.retrieve('prod_123'),
1514
+ stripe.prices.retrieve('price_123'),
1515
+ ]);
1516
+ ```
1517
+
1518
+ **Expand Related Objects:**
1519
+
1520
+ ```javascript
1521
+ // Instead of multiple requests
1522
+ const subscription = await stripe.subscriptions.retrieve('sub_123');
1523
+ const customer = await stripe.customers.retrieve(subscription.customer);
1524
+ const invoice = await stripe.invoices.retrieve(subscription.latest_invoice);
1525
+
1526
+ // Do this - single request with expand
1527
+ const subscription = await stripe.subscriptions.retrieve('sub_123', {
1528
+ expand: [
1529
+ 'customer',
1530
+ 'latest_invoice',
1531
+ 'latest_invoice.payment_intent',
1532
+ 'default_payment_method',
1533
+ ],
1534
+ });
1535
+
1536
+ // Access expanded objects
1537
+ console.log(subscription.customer.email);
1538
+ console.log(subscription.latest_invoice.amount_paid);
1539
+ ```
1540
+
1541
+ **Batch Operations:**
1542
+
1543
+ ```javascript
1544
+ // Create multiple objects efficiently
1545
+ async function createMultipleCustomers(customerData) {
1546
+ const BATCH_SIZE = 10;
1547
+ const results = [];
1548
+
1549
+ for (let i = 0; i < customerData.length; i += BATCH_SIZE) {
1550
+ const batch = customerData.slice(i, i + BATCH_SIZE);
1551
+ const batchPromises = batch.map(data =>
1552
+ stripe.customers.create(data)
1553
+ );
1554
+
1555
+ const batchResults = await Promise.allSettled(batchPromises);
1556
+ results.push(...batchResults);
1557
+
1558
+ // Small delay between batches to avoid rate limits
1559
+ if (i + BATCH_SIZE < customerData.length) {
1560
+ await new Promise(resolve => setTimeout(resolve, 100));
1561
+ }
1562
+ }
1563
+
1564
+ return results;
1565
+ }
1566
+ ```
1567
+
1568
+ ### TypeScript Usage
1569
+
1570
+ **Complete Type Safety:**
1571
+
1572
+ ```typescript
1573
+ import Stripe from 'stripe';
1574
+
1575
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
1576
+ apiVersion: '2025-02-24',
1577
+ });
1578
+
1579
+ // Full type inference
1580
+ async function createSubscription(
1581
+ customerId: string,
1582
+ priceId: string
1583
+ ): Promise<Stripe.Subscription> {
1584
+ const subscription = await stripe.subscriptions.create({
1585
+ customer: customerId,
1586
+ items: [{ price: priceId }],
1587
+ payment_behavior: 'default_incomplete',
1588
+ expand: ['latest_invoice.payment_intent'],
1589
+ });
1590
+
1591
+ return subscription;
1592
+ }
1593
+
1594
+ // Type-safe event handling
1595
+ async function handleWebhook(
1596
+ body: string | Buffer,
1597
+ signature: string
1598
+ ): Promise<void> {
1599
+ const event = stripe.webhooks.constructEvent(
1600
+ body,
1601
+ signature,
1602
+ process.env.STRIPE_WEBHOOK_SECRET!
1603
+ );
1604
+
1605
+ switch (event.type) {
1606
+ case 'payment_intent.succeeded': {
1607
+ const paymentIntent = event.data.object as Stripe.PaymentIntent;
1608
+ console.log(`PaymentIntent ${paymentIntent.id} succeeded`);
1609
+ break;
1610
+ }
1611
+ case 'customer.subscription.updated': {
1612
+ const subscription = event.data.object as Stripe.Subscription;
1613
+ console.log(`Subscription ${subscription.id} updated`);
1614
+ break;
1615
+ }
1616
+ default:
1617
+ console.log(`Unhandled event type: ${event.type}`);
1618
+ }
1619
+ }
1620
+
1621
+ // Custom types for your domain
1622
+ interface CreatePaymentParams {
1623
+ amount: number;
1624
+ currency: string;
1625
+ customerId?: string;
1626
+ metadata?: Record<string, string>;
1627
+ }
1628
+
1629
+ async function createPayment(
1630
+ params: CreatePaymentParams
1631
+ ): Promise<Stripe.PaymentIntent> {
1632
+ return await stripe.paymentIntents.create({
1633
+ amount: params.amount,
1634
+ currency: params.currency,
1635
+ customer: params.customerId,
1636
+ metadata: params.metadata,
1637
+ });
1638
+ }
1639
+ ```
1640
+
1641
+ ## 6. Production Checklist
1642
+
1643
+ ### Pre-Launch Verification
1644
+
1645
+ - [ ] Switched from test keys to live keys
1646
+ - [ ] Environment variables properly configured in production
1647
+ - [ ] Webhook endpoints registered and verified in Stripe Dashboard
1648
+ - [ ] Webhook signature verification implemented
1649
+ - [ ] HTTPS enabled on all endpoints
1650
+ - [ ] Error handling and logging configured
1651
+ - [ ] Rate limiting implemented
1652
+ - [ ] Idempotency keys used for critical operations
1653
+ - [ ] Payment confirmation flow tested end-to-end
1654
+ - [ ] Refund process tested
1655
+ - [ ] Subscription lifecycle tested (create, update, cancel)
1656
+ - [ ] Tax calculation configured (if applicable)
1657
+ - [ ] Email receipts enabled
1658
+ - [ ] Monitoring and alerting set up
1659
+ - [ ] PCI compliance requirements met
1660
+ - [ ] Terms of service and privacy policy updated
1661
+ - [ ] Customer support process for payment issues established
1662
+
1663
+ ### Monitoring
1664
+
1665
+ ```javascript
1666
+ // Monitor key metrics
1667
+ const metrics = {
1668
+ paymentIntentsCreated: 0,
1669
+ paymentIntentsSucceeded: 0,
1670
+ paymentIntentsFailed: 0,
1671
+ webhooksProcessed: 0,
1672
+ webhooksFailed: 0,
1673
+ apiErrors: 0,
1674
+ };
1675
+
1676
+ // Increment metrics in your code
1677
+ app.post('/create-payment', async (req, res) => {
1678
+ metrics.paymentIntentsCreated++;
1679
+
1680
+ try {
1681
+ const paymentIntent = await stripe.paymentIntents.create({
1682
+ amount: req.body.amount,
1683
+ currency: 'usd',
1684
+ });
1685
+
1686
+ return res.json(paymentIntent);
1687
+ } catch (err) {
1688
+ metrics.apiErrors++;
1689
+ logger.error('Payment creation failed', { error: err });
1690
+ return res.status(500).json({ error: 'Payment failed' });
1691
+ }
1692
+ });
1693
+
1694
+ // Expose metrics endpoint
1695
+ app.get('/metrics', (req, res) => {
1696
+ res.json(metrics);
1697
+ });
1698
+ ```
1699
+
1700
+ ### Disaster Recovery
1701
+
1702
+ ```javascript
1703
+ // Implement graceful degradation
1704
+ async function createPaymentWithFallback(params) {
1705
+ try {
1706
+ return await stripe.paymentIntents.create(params);
1707
+ } catch (err) {
1708
+ // Log error
1709
+ logger.error('Stripe API error', { error: err });
1710
+
1711
+ // If Stripe is down, queue for later processing
1712
+ if (err.type === 'StripeAPIError' || err.type === 'StripeConnectionError') {
1713
+ await queuePaymentForLater(params);
1714
+ return { status: 'queued', message: 'Payment will be processed shortly' };
1715
+ }
1716
+
1717
+ throw err;
1718
+ }
1719
+ }
1720
+ ```
1721
+
1722
+ ---
1723
+
1724
+ **Notes**
1725
+
1726
+ The Stripe API provides a comprehensive platform for payment processing, subscription management, and billing. The Node.js library (`stripe`) offers server-side functionality, while `@stripe/stripe-js` and `@stripe/react-stripe-js` provide client-side integration capabilities. Stripe uses date-based API versioning to ensure long-term compatibility while continuously adding new features. All payment data must be transmitted securely using HTTPS, and sensitive card information should only be handled by Stripe.js on the client side to maintain PCI compliance. Webhooks are essential for production deployments as they provide reliable event notifications independent of user sessions. The platform supports multiple payment methods, currencies, and billing models, making it suitable for businesses of all sizes. Always use test mode during development and thoroughly test your integration before switching to live mode.