Nuda Kit uses Stripe Checkout to handle payments securely. Users are redirected to Stripe's hosted checkout page, and subscriptions are created automatically via webhooks.
The checkout system provides:
Hosted Checkout
Multiple Plans
Promo Codes
Automatic Tax
User selects a plan
│
▼
┌─────────────────────────┐
│ POST /billing/ │
│ create-checkout │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Create/Get Stripe │
│ Customer ID │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Look up Plan by Key │ ◀── Get Stripe Price ID
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Create Checkout │
│ Session │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Return Checkout URL │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Redirect to Stripe │ ◀── User enters payment
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Payment Successful │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Webhook Received │ ◀── checkout.session.completed
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Create Subscription │ ◀── Stored in database
│ Record │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Redirect to Success │ ◀── /settings/billing?success=true
└─────────────────────────┘
| Method | Endpoint | Description |
|---|---|---|
POST | /billing/create-checkout | Creates a checkout session |
Request Body:
{
"plans": [
{ "key": "pro", "quantity": 1 }
]
}
Response:
{
"message": "checkout created",
"data": {
"checkoutUrl": "https://checkout.stripe.com/c/pay/..."
}
}
checkout.session.completed event| Feature | Description |
|---|---|
| Card Payments | Credit and debit card support |
| Billing Address | Required address collection |
| Promo Codes | Customers can apply discount codes |
| Automatic Tax | Tax calculated based on location |
| Success/Cancel URLs | Redirect handling built-in |
Nuda Kit supports two subscription types:
| Type | Description | Status Check |
|---|---|---|
| Recurring | Monthly/yearly subscriptions | active or trialing |
| Lifetime | One-time payment | paid |
| Status | Description |
|---|---|
active | Subscription is current and paid |
trialing | In free trial period |
past_due | Payment failed, grace period |
canceled | Subscription ended |
incomplete | Initial payment pending |
paused | Temporarily paused |
The checkout flow relies on webhooks to confirm payments:
| Event | Handler |
|---|---|
checkout.session.completed | Creates subscription record |
invoice.paid | Updates subscription status |
invoice.payment_failed | Marks payment as failed |
customer.subscription.updated | Syncs subscription changes |
customer.subscription.deleted | Marks subscription as canceled |
After checkout, users are redirected:
| Outcome | Redirect URL |
|---|---|
| Success | /settings/billing?success=true |
| Cancel | /settings/billing |
The success page shows a confirmation dialog.
| Card Number | Description |
|---|---|
4242 4242 4242 4242 | Successful payment |
4000 0000 0000 3220 | 3D Secure required |
4000 0000 0000 9995 | Payment declined |
stripe listen --forward-to localhost:3333/webhooks/stripe
.env