
Stripe
Exercise Stripe customers, checkout, payment intents, and webhooks against a local stateful API so payment flows work before you touch live Stripe keys.
Install
npx skills add https://github.com/vercel-labs/emulate --skill stripeWhat is this skill?
- Stateful in-memory customers, products, prices, checkout sessions, payment intents, charges, and payment methods
- Webhooks fire on state changes for realistic event-driven testing
- Hosted checkout UI in the browser to complete test payments
- Explicitly no real money processed—all SDK calls hit the emulator
- Stripe Node SDK requires passing a custom base URL at client construction
Adoption & trust: 97 installs on skills.sh; 1.3k GitHub stars; 2/3 security scanners passed (skills.sh audits).
Recommended Skills
Journey fit
Payment integration coding happens in Build; this skill keeps Stripe SDK traffic on localhost until you are ready for Ship-stage checkout and webhook verification tests. Integrations reflects configuring the Stripe client base URL, checkout flows, and webhook handlers—not growth analytics or live charge reconciliation.
Common Questions / FAQ
Is Stripe safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Stripe
# Stripe API Emulator Fully stateful Stripe API emulation. Customers, products, prices, checkout sessions, payment intents, charges, and payment methods persist in memory. Webhooks fire on state changes. The hosted checkout UI lets you complete payments in the browser. No real payments are processed. Every Stripe SDK call hits the emulator and produces realistic responses. ## Start ```bash # Stripe only npx emulate --service stripe # Default port (when run alone) # http://localhost:4000 ``` Or programmatically: ```typescript import { createEmulator } from 'emulate' const stripe = await createEmulator({ service: 'stripe', port: 4000 }) // stripe.url === 'http://localhost:4000' ``` ## Pointing Your App at the Emulator ### Stripe SDK The Stripe Node.js SDK does not read an environment variable for the base URL. You must pass it when constructing the client: ```typescript import Stripe from 'stripe' const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2024-12-18.acacia', host: 'localhost', port: 4000, protocol: 'http', }) ``` ### Embedded in Next.js (adapter-next) When using `@emulators/adapter-next`, the emulator runs inside your Next.js app at `/emulate/stripe`. The SDK needs to point at `localhost` with a proxy route to forward `/v1/*` calls to `/emulate/stripe/v1/*`: ```typescript // next.config.ts import { withEmulate } from '@emulators/adapter-next' export default withEmulate({ env: { STRIPE_SECRET_KEY: 'sk_test_emulated', }, }) ``` ```typescript // lib/stripe.ts import Stripe from 'stripe' const port = process.env.PORT ?? '3000' export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2024-12-18.acacia', host: 'localhost', port: parseInt(port, 10), protocol: 'http', }) ``` ```typescript // app/emulate/[...path]/route.ts import { createEmulateHandler } from '@emulators/adapter-next' import * as stripe from '@emulators/stripe' export const { GET, POST, PUT, PATCH, DELETE } = createEmulateHandler({ services: { stripe: { emulator: stripe, seed: { products: [ { id: 'prod_widget', name: 'Widget', description: 'A useful widget' }, ], prices: [ { id: 'price_widget', product_name: 'Widget', currency: 'usd', unit_amount: 1000 }, ], webhooks: [ { url: `http://localhost:${process.env.PORT ?? '3000'}/api/webhooks/stripe`, events: ['*'], }, ], }, }, }, }) ``` ```typescript // app/v1/[...path]/route.ts (proxy for Stripe SDK) const STRIPE_URL = `http://localhost:${process.env.PORT ?? '3000'}/emulate/stripe` async function handler(req: Request, ctx: { params: Promise<{ path: string[] }> }) { const { path } = await ctx.params const url = new URL(req.url) const target = `${STRIPE_URL}/v1/${path.join('/')}${url.search}` const res = await fetch(target, { method: req.method, headers: req.headers, body: req.body, duplex: 'half', } as any) return new Response(res.body, { status: res.status, statusText: res.statusText, headers: res.headers, }) } export { handler as GET, handler as POST, handler as PUT, handler as PATCH, handler as DELETE } ``` ### Direct fetch ```bash curl http://localhost:4000/v1/customers \ -H "Authorization: Bearer sk_test_emulated" ``` ## Seed Config Seed data is optional. All en