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