@stripe-sdk/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,700 @@
1
+ # @stripe-sdk/core
2
+
3
+ SDK Stripe **cle en main** pour vos applications. Integrez les paiements, abonnements, factures, webhooks, marketplace et plus en quelques lignes. Compatible React, Next.js, Vue, Angular et tout framework JavaScript.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @stripe-sdk/core stripe @stripe/stripe-js @stripe/react-stripe-js
9
+ ```
10
+
11
+ ## Configuration
12
+
13
+ ### 1. Variables d'environnement
14
+
15
+ ```env
16
+ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
17
+ STRIPE_SECRET_KEY=sk_test_...
18
+ STRIPE_WEBHOOK_SECRET=whsec_...
19
+ ```
20
+
21
+ ### 2. Initialisation (serveur)
22
+
23
+ ```ts
24
+ // lib/stripe.ts
25
+ import { initStripe } from '@stripe-sdk/core/server';
26
+
27
+ export const stripe = initStripe({
28
+ secretKey: process.env.STRIPE_SECRET_KEY!,
29
+ publishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
30
+ webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
31
+ });
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Paiements
37
+
38
+ ### Paiement simple avec formulaire integre
39
+
40
+ **Serveur** - Creer un PaymentIntent :
41
+
42
+ ```ts
43
+ // app/api/create-payment/route.ts
44
+ import '@/lib/stripe'; // initialise Stripe
45
+ import { createPaymentIntent } from '@stripe-sdk/core/server';
46
+
47
+ export async function POST(req: Request) {
48
+ const { amount } = await req.json();
49
+
50
+ const result = await createPaymentIntent({
51
+ amount, // en centimes (1000 = 10.00 EUR)
52
+ currency: 'eur',
53
+ });
54
+
55
+ if (result.error) {
56
+ return Response.json(result.error, { status: 400 });
57
+ }
58
+
59
+ return Response.json({ clientSecret: result.data.client_secret });
60
+ }
61
+ ```
62
+
63
+ **Client** - Formulaire de paiement :
64
+
65
+ ```tsx
66
+ // app/checkout/page.tsx
67
+ 'use client';
68
+ import { StripeElementsProvider, CheckoutForm } from '@stripe-sdk/core/client';
69
+
70
+ export default function CheckoutPage() {
71
+ const [clientSecret, setClientSecret] = useState('');
72
+
73
+ useEffect(() => {
74
+ fetch('/api/create-payment', {
75
+ method: 'POST',
76
+ body: JSON.stringify({ amount: 2000 }), // 20 EUR
77
+ })
78
+ .then(r => r.json())
79
+ .then(data => setClientSecret(data.clientSecret));
80
+ }, []);
81
+
82
+ if (!clientSecret) return <p>Loading...</p>;
83
+
84
+ return (
85
+ <StripeElementsProvider
86
+ publishableKey={process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!}
87
+ clientSecret={clientSecret}
88
+ >
89
+ <CheckoutForm
90
+ onSuccess={(id) => console.log('Paid!', id)}
91
+ onError={(err) => console.error(err)}
92
+ submitLabel="Payer 20 EUR"
93
+ showEmail
94
+ />
95
+ </StripeElementsProvider>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ### Checkout Session (page Stripe hebergee)
101
+
102
+ ```ts
103
+ // Server
104
+ import { createCheckoutSession } from '@stripe-sdk/core/server';
105
+
106
+ const result = await createCheckoutSession({
107
+ mode: 'payment',
108
+ lineItems: [{ priceId: 'price_xxx', quantity: 1 }],
109
+ successUrl: 'https://monsite.com/success?session_id={CHECKOUT_SESSION_ID}',
110
+ cancelUrl: 'https://monsite.com/cancel',
111
+ automaticTax: true,
112
+ allowPromotionCodes: true,
113
+ });
114
+
115
+ // Redirect le client vers result.data.url
116
+ ```
117
+
118
+ ```tsx
119
+ // Client - redirect vers Checkout
120
+ import { useCheckout } from '@stripe-sdk/core/client';
121
+
122
+ function BuyButton() {
123
+ const { redirectToCheckout, isLoading } = useCheckout({
124
+ publishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
125
+ });
126
+
127
+ const handleClick = async () => {
128
+ const res = await fetch('/api/create-checkout-session', { method: 'POST' });
129
+ const { sessionId } = await res.json();
130
+ await redirectToCheckout(sessionId);
131
+ };
132
+
133
+ return <button onClick={handleClick} disabled={isLoading}>Acheter</button>;
134
+ }
135
+ ```
136
+
137
+ ### Payment Link (sans code)
138
+
139
+ ```ts
140
+ import { createPaymentLink } from '@stripe-sdk/core/server';
141
+
142
+ const result = await createPaymentLink({
143
+ lineItems: [{ priceId: 'price_xxx', quantity: 1 }],
144
+ allowPromotionCodes: true,
145
+ afterCompletion: {
146
+ type: 'redirect',
147
+ redirectUrl: 'https://monsite.com/merci',
148
+ },
149
+ });
150
+
151
+ console.log(result.data.url); // Lien partageable
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Abonnements
157
+
158
+ ### Creer un abonnement
159
+
160
+ ```ts
161
+ import { createSubscription } from '@stripe-sdk/core/server';
162
+
163
+ const result = await createSubscription({
164
+ customerId: 'cus_xxx',
165
+ priceId: 'price_monthly_xxx',
166
+ trialPeriodDays: 14,
167
+ paymentBehavior: 'default_incomplete',
168
+ });
169
+
170
+ // result.data.latest_invoice.payment_intent.client_secret
171
+ // -> utiliser avec StripeElementsProvider pour confirmer le paiement
172
+ ```
173
+
174
+ ### Changer de plan
175
+
176
+ ```ts
177
+ import { updateSubscription } from '@stripe-sdk/core/server';
178
+
179
+ await updateSubscription({
180
+ subscriptionId: 'sub_xxx',
181
+ items: [{ id: 'si_xxx', priceId: 'price_annual_xxx' }],
182
+ prorationBehavior: 'create_prorations',
183
+ });
184
+ ```
185
+
186
+ ### Annuler / Reprendre
187
+
188
+ ```ts
189
+ import { cancelSubscription, resumeSubscription } from '@stripe-sdk/core/server';
190
+
191
+ // Annuler a la fin de la periode
192
+ await cancelSubscription({
193
+ subscriptionId: 'sub_xxx',
194
+ cancelAtPeriodEnd: true,
195
+ cancellationDetails: { feedback: 'too_expensive' },
196
+ });
197
+
198
+ // Reprendre
199
+ await resumeSubscription('sub_xxx');
200
+ ```
201
+
202
+ ### Composant PricingTable
203
+
204
+ ```tsx
205
+ import { PricingTable, type PricingPlan } from '@stripe-sdk/core/client';
206
+
207
+ const plans: PricingPlan[] = [
208
+ {
209
+ id: 'starter',
210
+ name: 'Starter',
211
+ priceId: 'price_starter',
212
+ amount: 900,
213
+ currency: 'eur',
214
+ interval: 'month',
215
+ features: ['5 projets', '1 Go stockage', 'Support email'],
216
+ },
217
+ {
218
+ id: 'pro',
219
+ name: 'Pro',
220
+ priceId: 'price_pro',
221
+ amount: 2900,
222
+ currency: 'eur',
223
+ interval: 'month',
224
+ features: ['Projets illimites', '100 Go stockage', 'Support prioritaire', 'API access'],
225
+ highlighted: true,
226
+ badge: 'Populaire',
227
+ },
228
+ ];
229
+
230
+ <PricingTable
231
+ plans={plans}
232
+ onSelectPlan={(plan) => handleSubscribe(plan.priceId)}
233
+ currentPlanId="starter"
234
+ />
235
+ ```
236
+
237
+ ### Composant SubscriptionManager
238
+
239
+ ```tsx
240
+ import { SubscriptionManager } from '@stripe-sdk/core/client';
241
+
242
+ <SubscriptionManager
243
+ subscription={{
244
+ id: 'sub_xxx',
245
+ status: 'active',
246
+ planName: 'Pro',
247
+ amount: 2900,
248
+ currency: 'eur',
249
+ interval: 'month',
250
+ currentPeriodEnd: '2025-03-01',
251
+ cancelAtPeriodEnd: false,
252
+ }}
253
+ onCancel={async (id) => {
254
+ await fetch(`/api/subscriptions/${id}/cancel`, { method: 'POST' });
255
+ }}
256
+ onResume={async (id) => {
257
+ await fetch(`/api/subscriptions/${id}/resume`, { method: 'POST' });
258
+ }}
259
+ onManageBilling={() => window.location.href = '/api/portal'}
260
+ />
261
+ ```
262
+
263
+ ---
264
+
265
+ ## Clients
266
+
267
+ ```ts
268
+ import {
269
+ createCustomer,
270
+ retrieveCustomer,
271
+ updateCustomer,
272
+ deleteCustomer,
273
+ listCustomers,
274
+ searchCustomers,
275
+ } from '@stripe-sdk/core/server';
276
+
277
+ // Creer
278
+ const { data: customer } = await createCustomer({
279
+ email: 'user@example.com',
280
+ name: 'John Doe',
281
+ metadata: { userId: 'usr_123' },
282
+ });
283
+
284
+ // Rechercher
285
+ const { data: results } = await searchCustomers("email:'user@example.com'");
286
+
287
+ // Mettre a jour
288
+ await updateCustomer({
289
+ customerId: 'cus_xxx',
290
+ name: 'Jane Doe',
291
+ defaultPaymentMethodId: 'pm_xxx',
292
+ });
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Portail Client
298
+
299
+ ```ts
300
+ import { createPortalSession } from '@stripe-sdk/core/server';
301
+
302
+ // API route
303
+ export async function POST(req: Request) {
304
+ const { customerId } = await req.json();
305
+ const result = await createPortalSession({
306
+ customerId,
307
+ returnUrl: 'https://monsite.com/account',
308
+ });
309
+ return Response.json({ url: result.data.url });
310
+ }
311
+
312
+ // Le client est redirige vers le portail Stripe pour gerer
313
+ // ses abonnements, moyens de paiement et factures.
314
+ ```
315
+
316
+ ---
317
+
318
+ ## Sauvegarder un moyen de paiement (SetupIntent)
319
+
320
+ ```ts
321
+ // Serveur
322
+ import { createSetupIntent } from '@stripe-sdk/core/server';
323
+
324
+ const result = await createSetupIntent({
325
+ customerId: 'cus_xxx',
326
+ usage: 'off_session', // pour les paiements futurs sans le client
327
+ });
328
+ ```
329
+
330
+ ```tsx
331
+ // Client
332
+ import { StripeElementsProvider, SetupForm } from '@stripe-sdk/core/client';
333
+
334
+ <StripeElementsProvider
335
+ publishableKey={process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!}
336
+ clientSecret={setupClientSecret}
337
+ >
338
+ <SetupForm
339
+ onSuccess={(setupId, pmId) => {
340
+ console.log('Saved!', pmId);
341
+ }}
342
+ submitLabel="Sauvegarder la carte"
343
+ />
344
+ </StripeElementsProvider>
345
+ ```
346
+
347
+ ---
348
+
349
+ ## Produits & Prix
350
+
351
+ ```ts
352
+ import {
353
+ createProduct,
354
+ createPrice,
355
+ listProducts,
356
+ listPrices,
357
+ } from '@stripe-sdk/core/server';
358
+
359
+ // Creer un produit avec prix par defaut
360
+ const { data: product } = await createProduct({
361
+ name: 'Plan Pro',
362
+ description: 'Acces complet a la plateforme',
363
+ defaultPriceData: {
364
+ unitAmount: 2900, // 29.00 EUR
365
+ currency: 'eur',
366
+ recurring: { interval: 'month' },
367
+ },
368
+ });
369
+
370
+ // Ajouter un prix annuel
371
+ await createPrice({
372
+ productId: product.id,
373
+ unitAmount: 29000, // 290.00 EUR
374
+ currency: 'eur',
375
+ recurring: { interval: 'year' },
376
+ lookupKey: 'pro_annual',
377
+ });
378
+
379
+ // Lister les produits actifs
380
+ const { data: products } = await listProducts({ active: true, limit: 20 });
381
+ ```
382
+
383
+ ---
384
+
385
+ ## Factures
386
+
387
+ ```ts
388
+ import {
389
+ createInvoice,
390
+ createInvoiceItem,
391
+ finalizeInvoice,
392
+ sendInvoice,
393
+ listInvoices,
394
+ getUpcomingInvoice,
395
+ } from '@stripe-sdk/core/server';
396
+
397
+ // Creer et envoyer une facture
398
+ const { data: invoice } = await createInvoice({
399
+ customerId: 'cus_xxx',
400
+ collectionMethod: 'send_invoice',
401
+ daysUntilDue: 30,
402
+ });
403
+
404
+ await createInvoiceItem({
405
+ customerId: 'cus_xxx',
406
+ invoiceId: invoice.id,
407
+ amount: 5000, // 50.00 EUR
408
+ currency: 'eur',
409
+ description: 'Consulting - Janvier 2025',
410
+ });
411
+
412
+ await finalizeInvoice(invoice.id);
413
+ await sendInvoice(invoice.id);
414
+
415
+ // Prochaine facture d'un abonnement
416
+ const { data: upcoming } = await getUpcomingInvoice('cus_xxx', 'sub_xxx');
417
+ ```
418
+
419
+ ---
420
+
421
+ ## Remboursements & Litiges
422
+
423
+ ```ts
424
+ import {
425
+ createRefund,
426
+ listRefunds,
427
+ retrieveDispute,
428
+ updateDispute,
429
+ } from '@stripe-sdk/core/server';
430
+
431
+ // Remboursement total
432
+ await createRefund({ paymentIntentId: 'pi_xxx' });
433
+
434
+ // Remboursement partiel
435
+ await createRefund({
436
+ paymentIntentId: 'pi_xxx',
437
+ amount: 500, // 5.00 EUR
438
+ reason: 'requested_by_customer',
439
+ });
440
+
441
+ // Repondre a un litige
442
+ await updateDispute({
443
+ disputeId: 'dp_xxx',
444
+ evidence: {
445
+ customerName: 'John Doe',
446
+ productDescription: 'Abonnement SaaS mensuel',
447
+ serviceDocumentation: 'file_xxx',
448
+ },
449
+ submit: true,
450
+ });
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Coupons & Codes Promo
456
+
457
+ ```ts
458
+ import {
459
+ createCoupon,
460
+ createPromotionCode,
461
+ listPromotionCodes,
462
+ } from '@stripe-sdk/core/server';
463
+
464
+ // Coupon -20%
465
+ const { data: coupon } = await createCoupon({
466
+ percentOff: 20,
467
+ duration: 'repeating',
468
+ durationInMonths: 3,
469
+ name: 'Lancement 2025',
470
+ });
471
+
472
+ // Code promo public
473
+ await createPromotionCode({
474
+ couponId: coupon.id,
475
+ code: 'LAUNCH20',
476
+ maxRedemptions: 100,
477
+ restrictions: {
478
+ firstTimeTransaction: true,
479
+ },
480
+ });
481
+ ```
482
+
483
+ ---
484
+
485
+ ## Stripe Connect (Marketplace)
486
+
487
+ ```ts
488
+ import {
489
+ createConnectAccount,
490
+ createAccountLink,
491
+ createTransfer,
492
+ getBalance,
493
+ } from '@stripe-sdk/core/server';
494
+
495
+ // Creer un compte vendeur
496
+ const { data: account } = await createConnectAccount({
497
+ type: 'express',
498
+ email: 'seller@example.com',
499
+ capabilities: {
500
+ cardPayments: { requested: true },
501
+ transfers: { requested: true },
502
+ },
503
+ });
504
+
505
+ // Lien d'onboarding
506
+ const { data: link } = await createAccountLink({
507
+ accountId: account.id,
508
+ refreshUrl: 'https://monsite.com/onboarding/refresh',
509
+ returnUrl: 'https://monsite.com/onboarding/complete',
510
+ type: 'account_onboarding',
511
+ });
512
+ // Rediriger le vendeur vers link.url
513
+
514
+ // Transferer des fonds
515
+ await createTransfer({
516
+ amount: 8000, // 80 EUR au vendeur
517
+ currency: 'eur',
518
+ destinationAccountId: account.id,
519
+ });
520
+
521
+ // Voir le solde
522
+ const { data: balance } = await getBalance();
523
+ ```
524
+
525
+ ---
526
+
527
+ ## Webhooks
528
+
529
+ ### Next.js App Router
530
+
531
+ ```ts
532
+ // app/api/webhooks/stripe/route.ts
533
+ import '@/lib/stripe';
534
+ import { createNextWebhookHandler } from '@stripe-sdk/core/webhooks';
535
+
536
+ export const POST = createNextWebhookHandler({
537
+ handlers: {
538
+ 'payment_intent.succeeded': async (event) => {
539
+ const pi = event.data.object;
540
+ console.log('Payment succeeded:', pi.id);
541
+ // Mettre a jour votre base de donnees
542
+ },
543
+
544
+ 'customer.subscription.created': async (event) => {
545
+ const sub = event.data.object;
546
+ console.log('New subscription:', sub.id);
547
+ },
548
+
549
+ 'customer.subscription.deleted': async (event) => {
550
+ const sub = event.data.object;
551
+ console.log('Subscription cancelled:', sub.id);
552
+ },
553
+
554
+ 'invoice.payment_failed': async (event) => {
555
+ const invoice = event.data.object;
556
+ console.log('Payment failed for:', invoice.customer);
557
+ // Envoyer un email au client
558
+ },
559
+
560
+ 'checkout.session.completed': async (event) => {
561
+ const session = event.data.object;
562
+ console.log('Checkout completed:', session.id);
563
+ },
564
+ },
565
+ onError: (error, event) => {
566
+ console.error('Webhook error:', error.message, event?.type);
567
+ },
568
+ });
569
+ ```
570
+
571
+ ### Next.js Pages Router
572
+
573
+ ```ts
574
+ // pages/api/webhooks/stripe.ts
575
+ import '@/lib/stripe';
576
+ import { createPagesWebhookHandler } from '@stripe-sdk/core/webhooks';
577
+
578
+ export const config = { api: { bodyParser: false } };
579
+
580
+ export default createPagesWebhookHandler({
581
+ handlers: {
582
+ 'payment_intent.succeeded': async (event) => { /* ... */ },
583
+ },
584
+ });
585
+ ```
586
+
587
+ ---
588
+
589
+ ## Next.js - Routes API pre-construites
590
+
591
+ ```ts
592
+ // app/api/create-payment-intent/route.ts
593
+ import '@/lib/stripe';
594
+ import { createPaymentIntentRoute } from '@stripe-sdk/core/next';
595
+
596
+ export const POST = createPaymentIntentRoute({
597
+ // Optionnel : modifier l'input avant creation
598
+ beforeCreate: async (input, request) => {
599
+ // Verifier l'authentification, forcer un montant, etc.
600
+ return { ...input, currency: 'eur' };
601
+ },
602
+ });
603
+ ```
604
+
605
+ ```ts
606
+ // app/api/create-checkout-session/route.ts
607
+ import '@/lib/stripe';
608
+ import { createCheckoutSessionRoute } from '@stripe-sdk/core/next';
609
+
610
+ export const POST = createCheckoutSessionRoute();
611
+ ```
612
+
613
+ ```ts
614
+ // app/api/create-portal-session/route.ts
615
+ import '@/lib/stripe';
616
+ import { createPortalSessionRoute } from '@stripe-sdk/core/next';
617
+
618
+ export const POST = createPortalSessionRoute();
619
+ ```
620
+
621
+ ---
622
+
623
+ ## Gestion des erreurs
624
+
625
+ Toutes les fonctions serveur retournent un `SDKResult<T>` :
626
+
627
+ ```ts
628
+ type SDKResult<T> =
629
+ | { data: T; error: null } // Succes
630
+ | { data: null; error: SDKError } // Erreur
631
+
632
+ type SDKError = {
633
+ message: string;
634
+ type: string;
635
+ code?: string;
636
+ statusCode?: number;
637
+ };
638
+ ```
639
+
640
+ ```ts
641
+ const result = await createPaymentIntent({ amount: 2000, currency: 'eur' });
642
+
643
+ if (result.error) {
644
+ console.error(result.error.message);
645
+ // "Your card was declined"
646
+ return;
647
+ }
648
+
649
+ console.log(result.data.id); // pi_xxx - TypeScript infere le type correct
650
+ ```
651
+
652
+ ---
653
+
654
+ ## Architecture
655
+
656
+ ```
657
+ src/
658
+ server/ # Code serveur uniquement
659
+ stripe-client.ts # Init & singleton Stripe
660
+ payments/ # PaymentIntent, Checkout, PaymentLink, SetupIntent
661
+ customers/ # CRUD clients + Portail
662
+ subscriptions/ # CRUD abonnements
663
+ products/ # Produits & Prix
664
+ invoices/ # Facturation
665
+ refunds/ # Remboursements & Litiges
666
+ connect/ # Marketplace, Transfers, Payouts, Balance
667
+ coupons/ # Coupons & Codes promo
668
+ webhooks/ # Handler avec verification de signature
669
+ client/ # Code client (React)
670
+ providers/ # StripeProvider, StripeElementsProvider
671
+ hooks/ # usePayment, useSetupIntent, useCheckout
672
+ components/ # CheckoutForm, SetupForm, PricingTable, SubscriptionManager
673
+ next/ # Utilitaires specifiques Next.js
674
+ index.ts # Server Actions, API route helpers
675
+ types/ # Types TypeScript complets
676
+ utils/ # Gestion d'erreurs
677
+ ```
678
+
679
+ ## Imports
680
+
681
+ ```ts
682
+ // Serveur uniquement
683
+ import { ... } from '@stripe-sdk/core/server';
684
+
685
+ // Client uniquement (React)
686
+ import { ... } from '@stripe-sdk/core/client';
687
+
688
+ // Webhooks
689
+ import { ... } from '@stripe-sdk/core/webhooks';
690
+
691
+ // Helpers Next.js
692
+ import { ... } from '@stripe-sdk/core/next';
693
+
694
+ // Tout (attention au tree-shaking)
695
+ import { ... } from '@stripe-sdk/core';
696
+ ```
697
+
698
+ ## Licence
699
+
700
+ MIT