Stripe Provider
Connect PayKit to Stripe with @paykitjs/stripe.
Setup
1. Install the provider
pnpm add @paykitjs/stripe2. Get your Stripe keys
From the Stripe Dashboard:
- Secret key (
sk_test_...orsk_live_...) - Webhook signing secret (
whsec_...), created when you add a webhook endpoint
3. Add environment variables
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."4. Configure the provider
import { createPayKit } from "paykitjs"
import { stripe } from "@paykitjs/stripe"
export const paykit = createPayKit({
// ...
provider: stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
}),
})Syncing Plans to Stripe
After defining or changing plans, sync them:
npx paykitjs pushThis creates/updates in Stripe:
- Products: one per plan
- Prices: one per plan with pricing
Check sync status:
npx paykitjs statusNote: Always run push after modifying plans. PayKit won't auto-sync on startup.
Webhook Setup
PayKit processes Stripe webhooks through its route handler. Configure Stripe to send webhooks to:
https://your-domain.com/paykit/api/webhookRequired Stripe webhook events
PayKit needs these events enabled in your Stripe webhook endpoint:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.paidinvoice.payment_failed
Local development
Use the Stripe CLI to forward webhooks locally:
stripe listen --forward-to localhost:3000/paykit/api/webhookThe CLI outputs a webhook signing secret (whsec_...). Use this as STRIPE_WEBHOOK_SECRET in development.
Customer Portal
Stripe's Customer Portal lets customers manage their billing. PayKit provides a wrapper:
Server-side:
const { url } = await paykit.customerPortal({
customerId: "user_123",
returnUrl: "https://example.com/billing",
})
// Redirect user to urlClient-side:
await paykitClient.customerPortal({
returnUrl: window.location.href,
})Configure the Customer Portal appearance and features in the Stripe Dashboard.
How PayKit Uses Stripe
PayKit maps its concepts to Stripe objects:
| PayKit | Stripe |
|---|---|
| Customer | Customer |
| Plan | Product |
| Plan price | Price |
| Subscription | Subscription |
| Checkout flow | Checkout Session |
PayKit stores its own records in your PostgreSQL database and keeps them in sync with Stripe via webhooks.
Test vs Live Mode
Use Stripe test keys (sk_test_...) during development. Switch to live keys (sk_live_...) for production.
PayKit doesn't distinguish between modes. It follows whatever key you provide.
Test cards: Use Stripe's test card numbers to simulate payments:
4242 4242 4242 4242succeeds4000 0000 0000 0002declines
Troubleshooting
| Problem | Fix |
|---|---|
| Webhooks not arriving | Verify endpoint URL matches basePath + /api/webhook |
| Webhook signature fails | Check STRIPE_WEBHOOK_SECRET matches the endpoint's signing secret |
| Plans not in Stripe | Run npx paykitjs push |
| Checkout redirects to wrong URL | Check successUrl and cancelUrl in subscribe() |
| Customer Portal not configured | Set it up in Stripe Dashboard > Settings > Billing > Portal |
| Local webhooks not working | Run stripe listen --forward-to localhost:3000/paykit/api/webhook |