PayKitv0.1 beta

Database

How PayKit stores and syncs billing state locally.

PayKit uses your app's PostgreSQL database to store billing state. Entitlement checks are fast local queries, not provider API calls. No round-trips to Stripe on every check().

Configuration

Pass a pg.Pool instance or a connection string to createPayKit.

paykit.ts
import { Pool } from "pg";

export const paykit = createPayKit({
  database: new Pool({
    connectionString: process.env.DATABASE_URL,
  }),
  // ...
});
paykit.ts
// Or pass a connection string directly
export const paykit = createPayKit({
  database: process.env.DATABASE_URL,
  // ...
});

Tables

PayKit creates tables prefixed with paykit_. The key ones are:

TableWhat it stores
paykit_customerCustomer records and provider ID mappings
paykit_subscriptionActive and past subscriptions
paykit_entitlementCurrent feature access and metered balances
paykit_productProducts synced from your config
paykit_featureFeatures defined in your plan config
paykit_invoiceInvoice records synced from the provider
paykit_payment_methodSaved payment methods
paykit_webhook_eventProcessed webhook events for deduplication

PayKit owns these tables. Don't write to them directly. Use the PayKit API.

Migrations

paykitjs push applies any pending migrations. Run it on initial setup and whenever you update your plan configuration.

pnpm dlx paykitjs push
bunx paykitjs push
npx paykitjs push

What's synced

PayKit keeps two sources of truth in sync:

From webhooks (provider to database): Subscriptions, invoices, payment methods, and customer-provider ID mappings are synced automatically when provider events arrive.

From your config (code to database): Plans, products, and features are synced from your createPayKit configuration when you run paykitjs push. Each time you change a plan and push, a new version is created. Previous versions are kept so running instances can continue serving existing subscriptions.

On this page