Billing

Checkout Flow

Stripe Checkout integration.

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.

Overview

The checkout system provides:

Hosted Checkout

Secure, PCI-compliant payment page hosted by Stripe.

Multiple Plans

Support for multiple products in a single checkout.

Promo Codes

Built-in support for Stripe promotion codes.

Automatic Tax

Stripe Tax automatically calculates and collects taxes.

Checkout Flow

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
└─────────────────────────┘

API Endpoint

MethodEndpointDescription
POST/billing/create-checkoutCreates a checkout session

Request Body:

{
  "plans": [
    { "key": "pro", "quantity": 1 }
  ]
}

Response:

{
  "message": "checkout created",
  "data": {
    "checkoutUrl": "https://checkout.stripe.com/c/pay/..."
  }
}

What's Included

Backend

  • CreateCheckoutController — Handles checkout session creation
  • StripeService — Checkout session with all features enabled
  • Webhook Handler — Processes checkout.session.completed event
  • Subscription Model — Stores subscription data
  • Automatic Stripe customer creation

Frontend

  • Billing Settings Page — Plan selection UI
  • Plan Cards — Display available plans with pricing
  • Success Dialog — Confirmation after successful checkout
  • Loading states and error handling

Checkout Features

FeatureDescription
Card PaymentsCredit and debit card support
Billing AddressRequired address collection
Promo CodesCustomers can apply discount codes
Automatic TaxTax calculated based on location
Success/Cancel URLsRedirect handling built-in

Subscription Types

Nuda Kit supports two subscription types:

TypeDescriptionStatus Check
RecurringMonthly/yearly subscriptionsactive or trialing
LifetimeOne-time paymentpaid

Subscription Statuses

StatusDescription
activeSubscription is current and paid
trialingIn free trial period
past_duePayment failed, grace period
canceledSubscription ended
incompleteInitial payment pending
pausedTemporarily paused

Webhook Events

The checkout flow relies on webhooks to confirm payments:

EventHandler
checkout.session.completedCreates subscription record
invoice.paidUpdates subscription status
invoice.payment_failedMarks payment as failed
customer.subscription.updatedSyncs subscription changes
customer.subscription.deletedMarks subscription as canceled
Webhooks must be configured for subscriptions to work. See Stripe Configuration.

Success & Cancel URLs

After checkout, users are redirected:

OutcomeRedirect URL
Success/settings/billing?success=true
Cancel/settings/billing

The success page shows a confirmation dialog.


Testing

Test Cards

Card NumberDescription
4242 4242 4242 4242Successful payment
4000 0000 0000 32203D Secure required
4000 0000 0000 9995Payment declined

Local Testing

  1. Run Stripe CLI to forward webhooks:
stripe listen --forward-to localhost:3333/webhooks/stripe
  1. Copy the webhook signing secret to .env
  2. Create a test checkout

Resources