PayKit Documentation

repository·main·Indexed 21 days ago

https://github.com/getpaykit/paykit

An embedded billing framework for TypeScript that allows developers to manage subscriptions, usage-based billing, and entitlements directly in their code and database. PayKit abstracts provider complexities (such as Stripe) using a code-first approach with functions like feature(), plan(), and createPayKit(). It includes a CLI for initialization, database migrations, and plan synchronization, as well as a type-safe client for managing subscriptions and customer portals in the browser.

Tokens
34.6K
Snippets
118
Records
160
Agent score
76%

What's inside PayKit

  1. What is PayKit?

    main
    PayKit is an embedded Stripe billing framework designed for TypeScript applications. It abstracts the complexity of Stripe's lifecycle code, allowing developers to manage subscriptions, usage-based billing, entitlements, and plans directly within their application logic. Instead of manually wiring up Stripe webhooks and API calls for every billing event, you use PayKit to handle the core billing workflows.
  2. What is PayKit?

    main

    PayKit is a TypeScript-first, server-side payments orchestration framework designed for modern SaaS. It acts as an orchestration layer between your application and payment providers.

    Key responsibilities:

    • Normalizes billing events from various providers.
    • Maintains a local, minimal billing state in your database.
    • Provides a provider-agnostic API for managing checkout, webhooks, and charges.

    Important distinction: PayKit does not process payments. It does not move money or run the actual checkout/vaulting logic; it coordinates the providers that do those tasks.

  3. Understand the technology stack in the web app

    main

    The web application is a T3 Stack project bootstrapped with create-t3-app. It utilizes the following core technologies:

    • Next.js: React framework for the frontend and API routes.
    • NextAuth.js: Authentication solution.
    • Prisma & Drizzle: ORMs for database management.
    • Tailwind CSS: Utility-first CSS framework for styling.
    • tRPC: End-to-end typesafe APIs.
  4. How upgrades and downgrades behave in PayKit

    main

    PayKit handles plan changes differently depending on whether the target plan is more expensive or less expensive than the current plan:

    Upgrades (Higher-priced plans)

    Upgrades happen immediately. The old plan ends and the new plan starts right away. Prorated amounts are handled based on your provider settings.

    Downgrades (Lower-priced plans)

    Downgrades are scheduled. The current plan remains active until the end of the current billing period. PayKit stores the target plan as a scheduled change and transitions the customer once the period ends via a provider webhook.

    Cancelling to a Free Plan

    To cancel a paid subscription, simply call subscribe() with the ID of your default free plan. This follows the downgrade pattern: the paid plan stays active until the end of the period, then automatically switches to free.

  5. Typography and Fonts

    main

    PayKit uses specific fonts and content rules:

    • Font Families: Use Geist (sans) and Geist Mono (mono) via the CSS variables --font-sans and --font-mono.
    • Text Sizes: Prefer standard Tailwind text sizes (text-xs, text-sm, text-base). Use arbitrary values only for sub-scale sizes.
    • Content Tone: Avoid using emdashes in user-facing text. Use periods, commas, or shorter sentences instead.
  6. Use the normalized model for event handling

    main
    PayKit uses a 'local-sync' model where incoming provider webhooks are transformed into a consistent, normalized format. When writing event handlers, you should always depend on PayKit event names and PayKit entity shapes rather than the raw JSON payload from the provider. This ensures your business logic remains decoupled from specific provider implementation details.
  7. Resume a subscription or change a scheduled downgrade

    main

    If a customer has a pending change (like a scheduled downgrade or cancellation), you can use subscribe() to modify or cancel that pending state:

    • Resume: Subscribing to the customer's currently active plan clears any pending downgrades or cancellations and resumes the subscription normally.
    • Change Target: If a downgrade is already scheduled, calling subscribe() with a different lower-priced plan will replace the existing scheduled target. Only one downgrade can be pending per group at a time.
    // Scenario 1: Resuming a subscription
    // Customer is on "pro" with a pending downgrade to "free"
    await paykit.subscribe({ customerId: "user_123", planId: "pro" });
    // Scheduled downgrade is cleared. Customer stays on "pro".
    
    // Scenario 2: Changing a scheduled target
    // Customer is on "ultra" with a pending downgrade to "free"
    await paykit.subscribe({ customerId: "user_123", planId: "pro" });
    // Scheduled target changes from "free" to "pro".
  8. How plan groups work

    main

    A group is a collection of plans that are mutually exclusive. A customer can only have one active plan per group at any given time.

    Usage Patterns:

    • Tiered access: A base group containing free, pro, and ultra plans.
    • Add-ons: An addons group for one-off upgrades.
    • Per-seat: A seats group for per-user pricing.

    Important Rules:

    • Every plan marked with default: true must belong to a group.
    • Only one plan per group can be designated as default: true.
    • When a customer has no active subscription in a group, PayKit treats them as being on the default plan without creating a formal subscription record until they subscribe.
  9. Understand metered feature balances

    main

    When checking metered features, the balance object provides the following properties:

    • limit: The total units allowed for the current period.
    • remaining: The number of units left before the limit is reached.
    • resetAt: The timestamp indicating when the balance will reset.
    • unlimited: A boolean indicating if the plan grants unlimited usage of this feature.