← VercelCONTENT HISTORY

Update to Vercel

Snapshot Sep 30, 2026 · 23:18 UTC · version 0.21.4

Collection source: not recorded for this historical snapshot. These snapshots do not have a confirmed matching collection source. Differences in file lists alone do not establish changes to the package.

WHAT CHANGED · RULE-BASED ANALYSIS

Supporting file metadata differs

Newly listed paths: agents/openai.yaml. This compares saved file lists, not package contents; a different collection source can change the list.

Observed in package metadata. These changes alone do not establish a new customer-facing feature.

Supporting files

Before

[]

After

[{"relative_path":"agents/openai.yaml","size_in_bytes":174}]

Compare saved observations

Download comparison JSON
Full technical diff · 1 changed fields

changed /included_files

BEFORE
[]
AFTER
[
  {
    "relative_path": "agents/openai.yaml",
    "size_in_bytes": 174
  }
]
Full snapshot data
{
  "name": "payments",
  "description": "Stripe payments integration guidance — native Vercel Marketplace setup, checkout sessions, webhook handling, subscription billing, and the Stripe SDK. Use when implementing payments, subscriptions, or processing transactions.",
  "included_files": [
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 174
    }
  ],
  "skill_md_contents": "---\nname: payments\ndescription: Stripe payments integration guidance — native Vercel Marketplace setup, checkout sessions, webhook handling, subscription billing, and the Stripe SDK. Use when implementing payments, subscriptions, or processing transactions.\nmetadata:\n  priority: 5\n  docs:\n    - \"https://docs.stripe.com\"\n    - \"https://docs.stripe.com/payments/quickstart\"\n  sitemap: \"https://docs.stripe.com/sitemap.xml\"\n  pathPatterns:\n    - 'app/api/webhook/stripe/**'\n    - 'app/api/webhooks/stripe/**'\n    - 'src/app/api/webhook/stripe/**'\n    - 'src/app/api/webhooks/stripe/**'\n    - 'pages/api/webhook/stripe.*'\n    - 'pages/api/webhooks/stripe.*'\n    - 'app/api/checkout/**'\n    - 'src/app/api/checkout/**'\n    - 'app/api/stripe/**'\n    - 'src/app/api/stripe/**'\n    - 'lib/stripe.*'\n    - 'src/lib/stripe.*'\n    - 'utils/stripe.*'\n    - 'src/utils/stripe.*'\n  bashPatterns:\n    - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*\\bstripe\\b'\n    - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*\\bstripe\\b'\n    - '\\bbun\\s+(install|i|add)\\s+[^\\n]*\\bstripe\\b'\n    - '\\byarn\\s+add\\s+[^\\n]*\\bstripe\\b'\n    - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@stripe/stripe-js\\b'\n    - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@stripe/stripe-js\\b'\n    - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@stripe/stripe-js\\b'\n    - '\\byarn\\s+add\\s+[^\\n]*@stripe/stripe-js\\b'\n    - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@stripe/react-stripe-js\\b'\n    - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@stripe/react-stripe-js\\b'\n    - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@stripe/react-stripe-js\\b'\n    - '\\byarn\\s+add\\s+[^\\n]*@stripe/react-stripe-js\\b'\n---\n\n# Stripe Payments Integration\n\nYou are an expert in Stripe payments for Vercel-deployed applications — covering the native Vercel Marketplace integration, Checkout Sessions, webhook handling, subscription billing, and the Stripe Node.js SDK.\n\n## Vercel Marketplace Setup (Recommended)\n\nStripe is a native Vercel Marketplace integration with sandbox provisioning and unified billing.\n\n### Install via Marketplace\n\n```bash\n# Install Stripe from Vercel Marketplace (auto-provisions sandbox + env vars)\nvercel integration add stripe\n```\n\nAuto-provisioned environment variables:\n- `STRIPE_SECRET_KEY` — server-side API key\n- `STRIPE_PUBLISHABLE_KEY` — client-side publishable key\n- `STRIPE_WEBHOOK_SECRET` — webhook endpoint signing secret\n\n### SDK Setup\n\n```bash\n# Server-side SDK\nnpm install stripe\n\n# Client-side SDK (for Stripe Elements / Checkout)\nnpm install @stripe/stripe-js @stripe/react-stripe-js\n```\n\n### Initialize the Stripe Client\n\n```ts\n// lib/stripe.ts\nimport Stripe from \"stripe\";\n\nexport const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {\n  apiVersion: \"2026-02-25.clover\",\n  typescript: true,\n});\n```\n\n## Checkout Sessions\n\n### Server Action (Recommended for 2026)\n\nServer Actions are the preferred pattern for creating Checkout Sessions in Next.js 15+, eliminating the need for API routes:\n\n```ts\n// app/actions/checkout.ts\n\"use server\";\nimport { redirect } from \"next/navigation\";\nimport { stripe } from \"@/lib/stripe\";\n\nexport async function createCheckoutSession(priceId: string) {\n  const session = await stripe.checkout.sessions.create({\n    mode: \"payment\",\n    line_items: [{ price: priceId, quantity: 1 }],\n    success_url: `${process.env.NEXT_PUBLIC_APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,\n    cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/cancel`,\n  });\n\n  redirect(session.url!);\n}\n```\n\n```tsx\n// app/pricing/page.tsx\nimport { createCheckoutSession } from \"@/app/actions/checkout\";\n\nexport default function PricingPage() {\n  return (\n    <form action={createCheckoutSession.bind(null, \"price_xxx\")}>\n      <button type=\"submit\">Buy Now</button>\n    </form>\n  );\n}\n```\n\n### Create a Checkout Session (API Route)\n\n```ts\n// app/api/checkout/route.ts\nimport { NextResponse } from \"next/server\";\nimport { stripe } from \"@/lib/stripe\";\n\nexport async function POST(req: Request) {\n  const { priceId } = await req.json();\n\n  const session = await stripe.checkout.sessions.create({\n    mode: \"payment\", // or \"subscription\" for recurring\n    payment_method_types: [\"card\"],\n    line_items: [{ price: priceId, quantity: 1 }],\n    success_url: `${process.env.NEXT_PUBLIC_APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,\n    cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/cancel`,\n  });\n\n  return NextResponse.json({ url: session.url });\n}\n```\n\n### Redirect to Checkout (Client)\n\n```tsx\n\"use client\";\nimport { loadStripe } from \"@stripe/stripe-js\";\n\nconst stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);\n\nexport function CheckoutButton({ priceId }: { priceId: string }) {\n  const handleCheckout = async () => {\n    const res = await fetch(\"/api/checkout\", {\n      method: \"POST\",\n      headers: { \"Content-Type\": \"application/json\" },\n      body: JSON.stringify({ priceId }),\n    });\n    const { url } = await res.json();\n    window.location.href = url;\n  };\n\n  return <button onClick={handleCheckout}>Subscribe</button>;\n}\n```\n\n## Webhook Handling\n\nStripe sends events to your webhook endpoint for asynchronous payment processing. Always verify the signature.\n\n```ts\n// app/api/webhook/stripe/route.ts\nimport { NextResponse } from \"next/server\";\nimport { stripe } from \"@/lib/stripe\";\nimport Stripe from \"stripe\";\n\nexport async function POST(req: Request) {\n  const body = await req.text();\n  const signature = req.headers.get(\"stripe-signature\")!;\n\n  let event: Stripe.Event;\n  try {\n    event = stripe.webhooks.constructEvent(\n      body,\n      signature,\n      process.env.STRIPE_WEBHOOK_SECRET!\n    );\n  } catch (err) {\n    return NextResponse.json({ error: \"Invalid signature\" }, { status: 400 });\n  }\n\n  switch (event.type) {\n    case \"checkout.session.completed\": {\n      const session = event.data.object as Stripe.Checkout.Session;\n      // Fulfill the order — update database, send confirmation, etc.\n      break;\n    }\n    case \"invoice.payment_succeeded\": {\n      const invoice = event.data.object as Stripe.Invoice;\n      // Handle successful subscription renewal\n      break;\n    }\n    case \"customer.subscription.deleted\": {\n      const subscription = event.data.object as Stripe.Subscription;\n      // Handle cancellation — revoke access\n      break;\n    }\n  }\n\n  return NextResponse.json({ received: true });\n}\n```\n\n**Important**: Webhook routes must read the raw body as text (not JSON) for signature verification. Do not add `bodyParser` or JSON middleware to webhook routes.\n\n## Subscription Billing\n\n### Create a Subscription Checkout\n\n```ts\nconst session = await stripe.checkout.sessions.create({\n  mode: \"subscription\",\n  line_items: [{ price: priceId, quantity: 1 }],\n  success_url: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard`,\n  cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/pricing`,\n});\n```\n\n### Customer Portal\n\nAllow customers to manage their subscriptions:\n\n```ts\n// app/api/portal/route.ts\nimport { stripe } from \"@/lib/stripe\";\n\nexport async function POST(req: Request) {\n  const { customerId } = await req.json();\n\n  const session = await stripe.billingPortal.sessions.create({\n    customer: customerId,\n    return_url: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard`,\n  });\n\n  return Response.json({ url: session.url });\n}\n```\n\n## Embedded Checkout (Recommended)\n\nStripe's Embedded Checkout renders inside your page via an iframe, keeping users on your domain while offloading PCI compliance to Stripe:\n\n```ts\n// app/actions/embedded-checkout.ts\n\"use server\";\nimport { stripe } from \"@/lib/stripe\";\n\nexport async function createEmbeddedCheckout(priceId: string) {\n  const session = await stripe.checkout.sessions.create({\n    mode: \"payment\",\n    line_items: [{ price: priceId, quantity: 1 }],\n    ui_mode: \"embedded\",\n    return_url: `${process.env.NEXT_PUBLIC_APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,\n  });\n\n  return { clientSecret: session.client_secret! };\n}\n```\n\n```tsx\n\"use client\";\nimport { loadStripe } from \"@stripe/stripe-js\";\nimport { EmbeddedCheckoutProvider, EmbeddedCheckout } from \"@stripe/react-stripe-js\";\nimport { createEmbeddedCheckout } from \"@/app/actions/embedded-checkout\";\n\nconst stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);\n\nexport function CheckoutEmbed({ priceId }: { priceId: string }) {\n  return (\n    <EmbeddedCheckoutProvider\n      stripe={stripePromise}\n      options={{ fetchClientSecret: () => createEmbeddedCheckout(priceId).then(r => r.clientSecret) }}\n    >\n      <EmbeddedCheckout />\n    </EmbeddedCheckoutProvider>\n  );\n}\n```\n\n## Stripe Elements (Custom Forms)\n\n```tsx\n\"use client\";\nimport { Elements, PaymentElement, useStripe, useElements } from \"@stripe/react-stripe-js\";\nimport { loadStripe } from \"@stripe/stripe-js\";\n\nconst stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);\n\nfunction CheckoutForm() {\n  const stripe = useStripe();\n  const elements = useElements();\n\n  const handleSubmit = async (e: React.FormEvent) => {\n    e.preventDefault();\n    if (!stripe || !elements) return;\n\n    const { error } = await stripe.confirmPayment({\n      elements,\n      confirmParams: { return_url: `${window.location.origin}/success` },\n    });\n\n    if (error) console.error(error.message);\n  };\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <PaymentElement />\n      <button type=\"submit\" disabled={!stripe}>Pay</button>\n    </form>\n  );\n}\n\nexport function PaymentForm({ clientSecret }: { clientSecret: string }) {\n  return (\n    <Elements stripe={stripePromise} options={{ clientSecret }}>\n      <CheckoutForm />\n    </Elements>\n  );\n}\n```\n\n## Environment Variables\n\n| Variable | Scope | Description |\n|----------|-------|-------------|\n| `STRIPE_SECRET_KEY` | Server | API secret key (starts with `sk_`) |\n| `STRIPE_PUBLISHABLE_KEY` | Client | Publishable key (starts with `pk_`) |\n| `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` | Client | Alias exposed to browser via Next.js |\n| `STRIPE_WEBHOOK_SECRET` | Server | Webhook signing secret (starts with `whsec_`) |\n\n## Cross-References\n\n- **Marketplace install and env var provisioning** → `⤳ skill: marketplace`\n- **Webhook route patterns** → `⤳ skill: routing-middleware`\n- **Environment variable management** → `⤳ skill: env-vars`\n- **Serverless function config** → `⤳ skill: vercel-functions`\n\n## Official Documentation\n\n- [Stripe + Vercel Marketplace](https://vercel.com/marketplace/stripe)\n- [Stripe Node.js SDK](https://docs.stripe.com/sdks)\n- [Stripe Checkout](https://docs.stripe.com/payments/checkout)\n- [Stripe Webhooks](https://docs.stripe.com/webhooks)\n- [Stripe Elements](https://docs.stripe.com/payments/elements)\n"
}

SHA-256: 6609d35499bf7713d2bc34ac08fbd8840a9e3d5f5fae7763fff911983d0b8e75