stripe-payments

Implement Stripe payment acceptance: Payment Intents, Setup Intents, Payment Methods, Checkout Sessions, Payment Element, Payment Links, and webhooks. Use when: (1) Accepting one-time payments (cards, wallets, bank transfers, BNPL), (2) Saving payment methods for later, (3) Building checkout flows (hosted or embedded), (4) Implementing 3D Secure / SCA, (5) Creating no-code Payment Links, (6) Handling payment webhooks and error states. Triggers on: accept payments, payment intent, checkout session, payment element, payment link, setup intent, save card, stripe elements, 3D secure, SCA.

zef-computers/drivers4 installsMITSynced Aug 26

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: stripe-payments
description: Implement Stripe payment acceptance: Payment Intents, Setup Intents, Payment Methods, Checkout Sessions, Payment Element, Payment Links, and webhooks. Use when: (1) Accepting one-time payments (cards, wallets, bank transfers, BNPL), (2) Saving payment methods for later, (3) Building checkout flows (hosted or embedded), (4) Implementing 3D Secure / SCA, (5) Creating no-code Payment Links, (6) Handling payment webhooks and error states. Triggers on: accept payments, payment intent, checkout session, payment element, payment link, setup intent, save card, stripe elements, 3D secure, SCA.
license: MIT
---

# Stripe Payments

Implement payment acceptance using Stripe's Payment Intents API, Checkout, Elements, and Payment Links.

## Priority Table

| Category | Impact | Rules | Key Concern |
|----------|--------|-------|-------------|
| Setup | HIGH | 3 | Integration path, Stripe.js loading, automatic payment methods |
| Payment Intents | HIGH | 4 | Idempotency, amounts, status handling, intent reuse |
| Checkout Sessions | HIGH | 4 | Webhook fulfillment, async payments, line items, session ID |
| Payment Element | MEDIUM | 4 | Return URL, submit state, wallet dedup, billing details |
| Security | HIGH | 4 | Client secret, SCA optimization, off-session recovery, metadata |
| Error Handling | HIGH | 3 | User messages, retry strategy, decline classification |
| Webhooks | HIGH | 3 | Signature verification, idempotent handlers, fast responses |

## Integration Decision Tree

```
How much UI control do you need?
|
+-- Minimal code / hosted page?
|   -> Checkout Sessions (references/checkout.md)
|
+-- No code at all?
|   -> Payment Links (references/payment-links.md)
|
+-- Embedded in your app with Stripe UI?
|   -> Payment Element (references/payment-element.md)
|
+-- Full custom UI?
    -> Payment Intents + confirm on client (references/payment-intents.md)
```

## Quick Reference

### Setup Rules
- **setup-automatic-payment-methods** - Use `automatic_payment_methods: { enabled: true }` instead of hardcoding `payment_method_types`
- **setup-load-stripe-js** - Always load Stripe.js from `js.stripe.com`, never self-host or bundle
- **setup-choose-integration** - Use Checkout Sessions for most apps; Payment Element for custom UX; Payment Links for no-code

### Payment Intent Rules
- **intent-use-idempotency-keys** - Always include idempotency keys on create, capture, and refund; derive from business IDs
- **intent-reuse-payment-intents** - Update existing PaymentIntents on cart changes instead of creating new ones
- **intent-handle-all-statuses** - Handle `succeeded`, `processing`, `requires_action`, `requires_payment_method`, `requires_capture`
- **intent-amounts-in-cents** - Pass amounts in smallest currency unit (cents): $20.00 = `amount: 2000`

### Checkout Session Rules
- **checkout-webhook-fulfillment** - Always use `checkout.session.completed` webhook for fulfillment, never the success URL
- **checkout-handle-async-payments** - Check `payment_status` in completed event; listen for `async_payment_succeeded` for bank transfers
- **checkout-retrieve-line-items** - Call `listLineItems()` separately; webhook payload does not include them
- **checkout-include-session-id** - Include `{CHECKOUT_SESSION_ID}` in success URL for status verification

### Payment Element Rules
- **element-provide-return-url** - Always provide `return_url` in `confirmPayment()`; redirect-based methods fail without it
- **element-disable-submit-button** - Disable submit button during processing to prevent double submissions
- **element-deduplicate-wallets** - Set `wallets: { applePay: 'never', googlePay: 'never' }` when using Express Checkout Element
- **element-collect-billing-separately** - If hiding billing fields, supply them in `confirmParams.payment_method_data.billing_details`

### Security Rules
- **security-protect-client-secret** - Never log, URL-embed, or persist `client_secret`; deliver via HTTPS JSON only
- **security-sca-setup-future-usage** - Set `setup_future_usage: 'off_session'` when saving cards for off-session charging
- **security-off-session-recovery** - Implement recovery flow for `authentication_required` errors on off-session payments
- **security-no-sensitive-metadata** - Never store PII, card numbers, passwords, or API keys in metadata

### Error Handling Rules
- **error-never-expose-raw-errors** - Show user-friendly messages; hide sensitive decline codes (`fraudulent`, `lost_card`, `stolen_card`)
- **error-retry-with-backoff** - Retry only connection/API/rate-limit errors with exponential backoff + jitter + idempotency keys
- **error-classify-decline-codes** - Route retryable declines (incorrect CVC) differently from terminal ones (insufficient funds)

### Webhook Rules
- **webhook-verify-signatures** - Use `express.raw()` for webhook route; JSON-parsed bodies fail signature verification
- **webhook-idempotent-handlers** - Check if event was already processed before fulfilling; Stripe retries on failure
- **webhook-return-200-quickly** - Acknowledge webhooks immediately; process heavy tasks asynchronously via job queue

## Quick Start: Checkout Session (Recommended for MVP)

### Server
```typescript
const session = await stripe.checkout.sessions.create({
  line_items: [{ price: 'price_xxx', quantity: 1 }],
  mode: 'payment', // or 'subscription' or 'setup'
  success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
  cancel_url: 'https://example.com/cancel',
});
// Redirect customer to session.url
```

### Webhook
```typescript
// Listen for checkout.session.completed
case 'checkout.session.completed':
  const session = event.data.object;
  await fulfillOrder(session);
  break;
```

## Quick Start: Payment Element (Recommended for Custom UX)

### Server - Create PaymentIntent
```typescript
const paymentIntent = await stripe.paymentIntents.create({
  amount: 2000, // $20.00 in cents
  currency: 'usd',
  automatic_payment_methods: { enabled: true },
});
return { clientSecret: paymentIntent.client_secret };
```

### Client - Mount Payment Element
```tsx
import { loadStripe } from '@stripe/stripe-js';
import { Elements, PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';

const stripePromise = loadStripe('pk_test_xxx');

function CheckoutForm() {
  const stripe = useStripe();
  const elements = useElements();

  const handleSubmit = async (e) => {
    e.preventDefault();
    const { error } = await stripe.confirmPayment({
      elements,
      confirmParams: { return_url: 'https://example.com/complete' },
    });
    if (error) setMessage(error.message);
  };

  return (
    <form onSubmit={handleSubmit}>
      <PaymentElement />
      <button>Pay</button>
    </form>
  );
}

function App({ clientSecret }) {
  return (
    <Elements stripe={stripePromise} options={{ clientSecret }}>
      <CheckoutForm />
    </Elements>
  );
}
```

## Payment Intent Lifecycle

```
requires_payment_method -> requires_confirmation -> requires_action -> processing -> succeeded
                                                                                  -> requires_payment_method (retry)
                                                                    -> canceled
```

Key states:
- `requires_action` - 3DS/SCA authentication needed (handled by `stripe.confirmPayment()`)
- `processing` - async payment methods (bank debits) still settling
- `succeeded` - funds captured, safe to fulfill

## Critical Webhooks

| Event | When | Action |
|-------|------|--------|
| `payment_intent.succeeded` | Payment confirmed | Fulfill order |
| `payment_intent.payment_failed` | Payment declined | Notify customer |
| `payment_intent.requires_action` | Needs 3DS | Client handles automatically |
| `charge.dispute.created` | Chargeback filed | See money-management reference |
| `checkout.session.completed` | Checkout finished | Fulfill + redirect |

## How to Use This Skill

1. **Start here** - Use the decision tree above to pick your integration path
2. **Follow rules** - Check the relevant rules in `rules/` for correct implementation patterns
3. **Deep dive** - Consult `references/` for comprehensive documentation on specific topics
4. **Test** - Use Stripe test cards (`4242 4242 4242 4242` for success, `4000 0025 0000 3155` for 3DS)

## References

- **references/payment-intents.md** - PaymentIntent lifecycle, confirmation, captures, cancellation
- **references/checkout.md** - Checkout Sessions, line items, modes, customization
- **references/payment-element.md** - Elements setup, appearance API, payment method config
- **references/payment-links.md** - No-code payment pages, configuration
- **references/payment-methods.md** - Cards, wallets (Apple/Google Pay), bank debits, BNPL
- **references/3d-secure.md** - SCA compliance, 3DS flows, exemptions
- **references/error-handling.md** - Error types, decline codes, retry strategies

More API Design skills

← All API Design skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY