### Client
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/quickstart.mdx
Upgrade to Pro button example.
```typescript
import { paykitClient } from "@/lib/paykit-client";
```
--------------------------------
### Local Setup
Source: https://github.com/getpaykit/paykit/blob/main/CONTRIBUTING.md
Commands to fork, clone, install dependencies, and build the project locally.
```bash
git clone https://github.comcom//paykit.git
cd paykit
pnpm install
pnpm build
```
--------------------------------
### src/routes/paykit.$.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Mount the PayKit request handler for Tanstack Start.
```typescript
import { createFileRoute } from "@tanstack/react-router";
import { paykit } from "@/lib/paykit";
async function handle({ request }: { request: Request }) {
return paykit.handler(request)
}
export const Route = createFileRoute("/paykit/$")({
server: {
handlers: {
GET: handle,
POST: handle,
},
},
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Initializes PayKit with defined products.
```typescript
import { free, pro } from "./products";
export const paykit = createPayKit({
// ...
products: [free, pro],
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/plugins.mdx
Example of installing and using a plugin with createPayKit.
```typescript
import { dash } from "@paykitjs/dash";
export const paykit = createPayKit({
// ...
plugins: [dash()],
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Create a PayKit instance.
```typescript
import { createPayKit } from "paykitjs";
export const paykit = createPayKit({
// ...
});
```
--------------------------------
### Lemon Squeezy Provider Setup
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/lemonsqueezy.mdx
Example of how to set up the Lemon Squeezy provider with your API key and webhook secret.
```typescript
import { lemonSqueezy } from "paykitjs/providers/lemonsqueezy";
const provider = lemonSqueezy({
apiKey: process.env.LEMONSQUEEZY_API_KEY!,
webhookSecret: process.env.LEMONSQUEEZY_WEBHOOK_SECRET!,
});
```
--------------------------------
### Server
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/quickstart.mdx
Call upsertCustomer when the user is created, or before the purchase. Then, pass customerId to subscribe.
```typescript
await paykit.upsertCustomer({
id: "user_123", // user or organization id
email: "jane@example.com",
name: "Jane Doe",
});
// then, pass `customerId` to purchase:
await paykit.subscribe({ customerId: "user_123", planId: "pro" })
```
--------------------------------
### paykitjs init
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/cli.mdx
Initializes a new PayKit project with an interactive setup wizard.
```bash
paykitjs init
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Configure PayKit with a database connection.
```typescript
import { Pool } from "pg";
export const paykit = createPayKit({
// ...
database: new Pool({
connectionString: process.env.DATABASE_URL!,
}),
});
```
--------------------------------
### Paddle Provider Setup
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/paddle.mdx
Example of how to set up the Paddle provider with your API key and webhook secret.
```typescript
import { paddle } from "paykitjs/providers/paddle";
const provider = paddle({
apiKey: process.env.PADDLE_API_KEY!,
webhookSecret: process.env.PADDLE_WEBHOOK_SECRET!,
});
```
--------------------------------
### products.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Defines products and features for PayKit billing.
```typescript
import { feature, plan } from "paykitjs";
const messages = feature({ id: "messages", type: "metered" });
const proModels = feature({ id: "pro_models", type: "boolean" });
export const free = plan({
id: "free",
name: "Free",
group: "base",
default: true,
includes: [
messages({ limit: 100, reset: "month" })
],
});
export const pro = plan({
id: "pro",
name: "Pro",
group: "base",
price: { amount: 19, interval: "month" },
includes: [
messages({ limit: 2000, reset: "month" }),
proModels()
],
});
```
--------------------------------
### Testing with Vitest
Source: https://github.com/getpaykit/paykit/blob/main/CONTRIBUTING.md
Example of how to run specific tests or patterns using Vitest.
```bash
vitest /path/to/test-file -t "pattern"
```
--------------------------------
### Planned setup
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/creem.mdx
This code snippet shows the planned setup for the Creem provider using paykitjs.
```typescript
import { creem } from "paykitjs/providers/creem";
const provider = creem({
apiKey: process.env.CREEM_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
});
```
--------------------------------
### Server
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/quickstart.mdx
To subscribe a customer to a plan, call subscribe with the plan ID. For paid plans without a saved payment method, it returns a paymentUrl pointing to the provider checkout.
```typescript
const result = await paykit.subscribe({
customerId: "user_123",
planId: "pro",
successUrl: "https://myapp.com/billing/success",
cancelUrl: "https://myapp.com/billing",
});
if (result.paymentUrl) {
// redirect user to provider checkout
}
```
--------------------------------
### Client
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/quickstart.mdx
The client's customer is automatically identified. You don't need to pass customerId to purchase on the client.
```typescript
// server.ts
const paykit = createPayKit({
// ...
// client's customer is automatically identified here:
identify: async ({ headers }) => {
const session = await auth.api.getSession({ headers });
if (!session) return null;
return {
customerId: session.user.id, // user or organization id
email: session.user.email,
name: session.user.name,
};
},
});
// client.ts
const paykitClient = createPayKitClient();
// so you don't need to pass `customerId` to purchase on client:
await paykitClient.subscribe({ planId: "pro" })
```
--------------------------------
### terminal
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/guides/skills.mdx
Install the PayKit skills using the skills CLI.
```bash
npx skills add getpaykit/skills
```
--------------------------------
### server.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Mount the PayKit request handler for other frameworks.
```typescript
import { paykit } from "./paykit";
// paykit.handler: (request: Request) => Promise
// Mount it on any path that catches /paykit/*
app.all("/paykit/*", (req) => paykit.handler(req));
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Configure server-side authentication for client requests.
```typescript
export const paykit = createPayKit({
// ...
identify: async ({ headers }) => {
const session = await auth.api.getSession({ headers });
if (!session) return null;
return {
customerId: session.user.id,
email: session.user.email,
name: session.user.name,
// Just pass user's data, and Stripe customer gets synced automatically!
};
},
});
```
--------------------------------
### Client-side subscription
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/subscriptions.mdx
Example of subscribing to a plan on the client.
```tsx
const { paymentUrl } = await paykitClient.subscribe({
planId: "pro",
successUrl: "/billing/success",
cancelUrl: "/billing",
});
if (paymentUrl) {
window.location.href = paymentUrl;
}
```
--------------------------------
### src/app/paykit/[[...slug]]/route.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/installation.mdx
Mount the PayKit request handler for Next.js.
```typescript
import { paykitHandler } from "paykitjs/handlers/next";
import { paykit } from "@/lib/paykit";
export const { GET, POST } = paykitHandler(paykit);
```
--------------------------------
### Server-side subscription
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/subscriptions.mdx
Example of subscribing to a plan on the server.
```typescript
const result = await paykit.subscribe({
customerId: "user_123",
planId: "pro",
successUrl: "https://myapp.com/billing/success",
cancelUrl: "https://myapp.com/billing",
});
if (result.paymentUrl) {
// Redirect user to provider checkout
}
```
--------------------------------
### Conventional Commits Example
Source: https://github.com/getpaykit/paykit/blob/main/CONTRIBUTING.md
Examples of commit messages following the Conventional Commits specification.
```bash
feat(stripe): add webhook handler
fix(paykit): correct subscription renewal logic
docs: update README setup steps
chore: bump pnpm to 11.1.1
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/get-started/quickstart.mdx
Listen to events: To react to billing changes, add the on option to your PayKit instance. The customer.updated event fires after any subscription or entitlement change.
```typescript
export const paykit = createPayKit({
// ...
on: { // [!code highlight]
"customer.updated": ({ payload }) => { // [!code highlight]
console.log("billing changed for", payload.customerId); // [!code highlight]
}, // [!code highlight]
}, // [!code highlight]
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/plugins.mdx
Example of configuring authorization for the dashboard plugin.
```typescript
import { dash } from "@paykitjs/dash";
export const paykit = createPayKit({
// ...
plugins: [
dash({
authorize: async (request) => {
const session = await auth.api.getSession({
headers: request.headers,
});
if (!session) throw new Error("Not authenticated");
},
}),
],
});
```
--------------------------------
### products.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/plans-and-features.mdx
Example of a default plan within a group.
```typescript
export const free = plan({
id: "free",
group: "base",
default: true,
// ...
});
```
--------------------------------
### Register multiple adapters
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/multi-provider-setup.mdx
Configure PayKit with multiple payment providers like Stripe and PayPal.
```typescript
import { createPayKit } from "paykitjs";
import { postgresStorage } from "paykitjs/storage/postgres";
import { paypal } from "paykitjs/providers/paypal";
import { stripe } from "paykitjs/providers/stripe";
export const paykit = createPayKit({
storage: postgresStorage({
connectionString: process.env.DATABASE_URL!,
}),
providers: [
stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
}),
paypal({
clientId: process.env.PAYPAL_CLIENT_ID!,
clientSecret: process.env.PAYPAL_CLIENT_SECRET!,
webhookId: process.env.PAYPAL_WEBHOOK_ID!,
}),
],
});
```
--------------------------------
### Product arrays
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/typescript.mdx
Example of passing products to `createPayKit` as an array of values returned by `plan(...)`.
```typescript
import { free, pro, ultra } from "./products";
export const paykit = createPayKit({
products: [free, pro, ultra],
// ...
});
```
--------------------------------
### PayKit Configuration
Source: https://github.com/getpaykit/paykit/blob/main/README.md
Example of how to configure PayKit with Stripe, defining features, plans, and products.
```typescript
import { stripe } from "@paykitjs/stripe";
import { createPayKit, feature, plan } from "paykitjs";
const messages = feature({ id: "messages", type: "metered" });
const free = plan({
id: "free",
group: "base",
default: true,
includes: [messages({ limit: 100, reset: "month" })],
});
const pro = plan({
id: "pro",
group: "base",
price: { amount: 19, interval: "month" },
includes: [messages({ limit: 2_000, reset: "month" })],
});
export const paykit = createPayKit({
provider: stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
}),
database: process.env.DATABASE_URL!,
products: [free, pro],
});
```
--------------------------------
### Choose the provider at the call site
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/multi-provider-setup.mdx
Specify the provider to use when creating a checkout session.
```typescript
await paykit.checkout.create({
providerId: "paypal",
customerId: "cust_abc",
amount: 2900,
description: "Starter plan",
successURL: "https://app.example.com/billing/success",
});
```
--------------------------------
### PayPal Provider Initialization
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/paypal.mdx
Example of how to initialize the PayPal provider with necessary credentials.
```typescript
import { paypal } from "paykitjs/providers/paypal";
const provider = paypal({
clientId: process.env.PAYPAL_CLIENT_ID!,
clientSecret: process.env.PAYPAL_CLIENT_SECRET!,
webhookId: process.env.PAYPAL_WEBHOOK_ID!,
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/payment-providers.mdx
Example of initializing PayKit with the Stripe provider.
```typescript
import { stripe } from "@paykitjs/stripe";
export const paykit = createPayKit({
// ...
provider: stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
}),
});
```
--------------------------------
### paykitjs status
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/cli.mdx
Validates the PayKit setup without making changes.
```bash
paykitjs status
```
--------------------------------
### src/lib/paykit-client.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/client.mdx
Install the client and create an instance typed to your server paykit export. It uses `import type` to carry server types into the browser without bundling any server code.
```typescript
import { createPayKitClient } from "paykitjs/client";
import type { paykit } from "@/server/paykit";
export const paykitClient = createPayKitClient();
```
--------------------------------
### Resume subscription
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/subscriptions.mdx
Example of resuming a subscription by subscribing to the current active plan when a downgrade is pending.
```typescript
// 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".
```
--------------------------------
### paykitjs status with throw
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/cli.mdx
Validates the PayKit setup and exits with code 1 on failures, useful for CI pipelines.
```bash
paykitjs status --throw
```
--------------------------------
### Getting a customer
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/customers.mdx
The `getCustomer` function returns the customer along with their active subscriptions and entitlements. `subscriptions` is an array of `{ planId, status, cancelAtPeriodEnd, currentPeriodStart, currentPeriodEnd }`. `entitlements` is a record keyed by feature ID with `{ balance, limit, usage, unlimited, nextResetAt }`.
```typescript
const customer = await paykit.getCustomer({ id: "user_123" });
// customer.subscriptions: active subscriptions with planId, status, period dates
// customer.entitlements: feature balances keyed by feature ID
```
--------------------------------
### Compile-time error example
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/typescript.mdx
Illustrates a compile-time error when an invalid plan ID is used.
```typescript
// Type error: "typo" is not assignable to "free" | "pro" | "ultra"
await paykit.subscribe({ customerId: "user_123", planId: "typo" });
```
--------------------------------
### Start the attach flow
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/save-a-payment-method.mdx
This code snippet initiates the process of attaching a payment method for a customer.
```typescript
const result = await paykit.paymentMethod.attach({
providerId: "stripe",
customerId: customer.id,
returnURL: "https://app.example.com/settings/billing",
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/stripe.mdx
Example of configuring PayKit with Stripe, enabling Managed Payments and specifying a preview API version.
```typescript
export const paykit = createPayKit({
// ...
provider: stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
apiVersion: "2026-03-04.preview",
managedPayments: true,
}),
});
```
--------------------------------
### Regression Test Example
Source: https://github.com/getpaykit/paykit/blob/main/CONTRIBUTING.md
JSDoc comment format for referencing issue URLs in regression tests.
```typescript
/** @see https://github.com/getpaykit/paykit/issues/123 */
it("does not throw when ...", () => {
```
--------------------------------
### Using internal IDs
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/payment-providers.mdx
Example of how the application uses its own IDs for customer and plan, while PayKit handles the mapping to provider-native IDs internally.
```typescript
// Your app always uses its own IDs
await paykit.subscribe({ customerId: "user_123", planId: "pro" });
// PayKit resolves the Stripe customer and price internally
```
--------------------------------
### Sync the app customer
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/create-your-first-checkout.mdx
Syncs a customer with PayKit, returning the PayKit customer ID.
```typescript
const customer = await paykit.customer.sync({
referenceId: "user_123",
email: "jane@example.com",
});
```
--------------------------------
### Architecture Diagram
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-index.mdx
Illustrates the flow of information and control between your application, PayKit Core, Provider Adapter, and the External Provider.
```txt
Your App -> PayKit Core -> Provider Adapter -> External Provider
```
--------------------------------
### Create checkout
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/create-your-first-checkout.mdx
Creates a checkout session with the specified provider and customer.
```typescript
const checkout = await paykit.checkout.create({
providerId: "stripe",
customerId: customer.id,
amount: 2900,
description: "Starter plan",
successURL: "https://app.example.com/billing/success",
cancelURL: "https://app.example.com/billing/cancel",
attachMethod: true,
});
```
--------------------------------
### React to completion
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/create-your-first-checkout.mdx
Handles the 'checkout.completed' event to grant access after a successful checkout.
```typescript
const paykit = createPayKit({
// ...
on: {
"checkout.completed": async ({ customer }) => {
await grantStarterAccess(customer.referenceId);
},
},
});
```
--------------------------------
### paykitjs push with next build
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/cli.mdx
Runs paykitjs push and then builds the Next.js application, skipping confirmation prompts.
```bash
paykitjs push -y && next build
```
--------------------------------
### Change scheduled downgrade target
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/subscriptions.mdx
Example of changing the scheduled downgrade target when one is already pending.
```typescript
// 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".
```
--------------------------------
### src/app/paykit/[[...slug]]/route.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/handle-webhooks.mdx
Mount the PayKit route.
```typescript
import { paykit } from "@/lib/paykit";
import { paykitHandler } from "paykitjs/handlers/next";
export const { GET, POST } = paykitHandler(paykit);
```
--------------------------------
### src/lib/paykit-client.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/typescript.mdx
Demonstrates creating a PayKit client SDK that inherits types from the server instance for client-side type safety.
```typescript
// Client inherits server types
import type { paykit } from "@/server/paykit";
const client = createPayKitClient();
await client.subscribe({ planId: "pro" }); // ✓ type-safe
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/plans-and-features.mdx
Pass your products array to createPayKit for type-safe plan and feature IDs.
```typescript
import { free, pro, ultra } from "./products";
export const paykit = createPayKit({
// ...
products: [free, pro, ultra],
});
// Plan and feature IDs are now type-safe:
await paykit.subscribe({ customerId: "user_123", planId: "pro" }); // ✓
await paykit.subscribe({ customerId: "user_123", planId: "typo" }); // ✗ type error
```
--------------------------------
### paykitjs push
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/cli.mdx
Applies pending database migrations and syncs plan definitions to the database and payment provider.
```bash
paykitjs push
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/typescript.mdx
Demonstrates how PayKit infers plan and feature IDs from the products configuration, providing compile-time safety for method calls.
```typescript
// Types are inferred from your products
export const paykit = createPayKit({
products: [free, pro, ultra],
// ...
});
// planId only accepts "free" | "pro" | "ultra"
await paykit.subscribe({ customerId: "user_123", planId: "pro" });
// featureId only accepts "messages" | "pro_models" | "priority_support"
await paykit.check({ customerId: "user_123", featureId: "messages" });
```
--------------------------------
### Listing customers
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/customers.mdx
The `listCustomers` function returns a paginated list. You can filter by plan to find everyone on a specific tier.
```typescript
const { data, total, hasMore } = await paykit.listCustomers({
limit: 50,
offset: 0,
planIds: ["pro", "ultra"],
});
```
--------------------------------
### Subscribe to a paid plan (Server)
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/flows/subscription-billing.mdx
Initiates a subscription to a paid plan. If a payment URL is returned, the user is redirected to complete the checkout process.
```typescript
const result = await paykit.subscribe({
customerId: "user_123",
planId: "pro",
successUrl: "https://myapp.com/billing/success",
cancelUrl: "https://myapp.com/billing",
});
if (result.paymentUrl) {
return Response.redirect(result.paymentUrl);
}
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/database.mdx
Or pass a connection string directly to createPayKit.
```typescript
// Or pass a connection string directly
export const paykit = createPayKit({
database: process.env.DATABASE_URL,
// ...
});
```
--------------------------------
### Creating customers
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/customers.mdx
The `upsertCustomer` function creates a customer if they don't exist, or updates their details if they do. If a default plan is configured, newly created customers are automatically subscribed to it.
```typescript
await paykit.upsertCustomer({
id: "user_123",
email: "jane@example.com",
name: "Jane Doe",
});
```
--------------------------------
### Create a customer (Client)
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/flows/subscription-billing.mdx
Sets up the `identify` function on the PayKit instance for automatic customer creation on the client-side. It retrieves user session information to identify the customer.
```typescript
export const paykit = createPayKit({
// ...
identify: async ({ headers }) => {
const session = await auth.api.getSession({ headers });
if (!session) return null;
return {
customerId: session.user.id,
email: session.user.email,
name: session.user.name,
};
},
});
```
--------------------------------
### Development Commands
Source: https://github.com/getpaykit/paykit/blob/main/CONTRIBUTING.md
Common commands for development, including watch mode, type checking, linting, and formatting.
```bash
pnpm dev # Watch mode (Turbo)
pnpm typecheck # tsc --build
pnpm lint # oxlint --deny-warnings
pnpm lint:fix # Auto-fix lint issues
pnpm format # oxfmt
pnpm format:check # Check formatting without writing
```
--------------------------------
### Custom base URL
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/client.mdx
If you changed `basePath` on your server instance, pass the PayKit root URL to the client.
```ts
export const paykitClient = createPayKitClient({
baseURL: "/custom",
});
```
--------------------------------
### Define plans
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/flows/subscription-billing.mdx
Defines features and plans for subscription tiers, including a free tier and a paid 'Pro' tier with metered features and boolean features.
```typescript
import { feature, plan } from "paykitjs";
const messages = feature({ id: "messages", type: "metered" });
const proModels = feature({ id: "pro_models", type: "boolean" });
export const free = plan({
id: "free",
name: "Free",
group: "base",
default: true,
includes: [messages({ limit: 100, reset: "month" })],
});
export const pro = plan({
id: "pro",
name: "Pro",
group: "base",
price: { amount: 19, interval: "month" },
includes: [
messages({ limit: 2_000, reset: "month" }),
proModels(),
],
});
```
```typescript
import { free, pro } from "./products";
export const paykit = createPayKit({
// ...
products: [free, pro],
});
```
--------------------------------
### products.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/plans-and-features.mdx
Define plans with IDs, names, groups, pricing, and included features.
```typescript
export const free = plan({
id: "free",
name: "Free",
group: "base",
default: true,
includes: [
messages({ limit: 100, reset: "month" }),
],
});
export const pro = plan({
id: "pro",
name: "Pro",
group: "base",
price: { amount: 19, interval: "month" },
includes: [
messages({ limit: 2_000, reset: "month" }),
proModels(),
],
});
export const ultra = plan({
id: "ultra",
name: "Ultra",
group: "base",
price: { amount: 49, interval: "month" },
includes: [
messages({ limit: 10_000, reset: "month" }),
proModels(),
prioritySupport(),
],
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/database.mdx
Pass a pg.Pool instance to createPayKit.
```typescript
import { Pool } from "pg";
export const paykit = createPayKit({
database: new Pool({
connectionString: process.env.DATABASE_URL,
}),
// ...
});
```
--------------------------------
### Pick a method
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/charge-a-saved-payment-method.mdx
Selects the default payment method or the first available one.
```typescript
const method = methods.find((item) => item.isDefault) ?? methods[0];
if (!method) {
throw new Error("No saved payment method");
}
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/customers.mdx
The `identify` option on `createPayKit` resolves the authenticated customer from the incoming request. `identify` is required if you're using the client SDK or the built-in HTTP router. If it returns `null`, the request is treated as unauthenticated and rejected.
```typescript
export const paykit = createPayKit({
// ...
identify: async (request) => {
const session = await auth.api.getSession({ headers: request.headers });
if (!session) return null;
return {
customerId: session.user.id,
email: session.user.email,
name: session.user.name,
};
},
});
```
--------------------------------
### Subscribe from a React component
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/client.mdx
Subscribe from a React component
```tsx
// Subscribe from a React component
```
--------------------------------
### Upgrade Subscription
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/flows/subscription-billing.mdx
Upgrades a customer to a higher-priced plan immediately.
```typescript
await paykit.subscribe({
customerId: "user_123",
planId: "pro", // moving up from free
});
// subscription is active immediately
```
--------------------------------
### Server
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/polar.mdx
Generate a customer portal URL on the server.
```typescript
const { url } = await paykit.customerPortal({
customerId: "user_123",
returnUrl: "https://myapp.com/billing",
});
// redirect the user to `url`
```
--------------------------------
### Resume Subscription
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/flows/subscription-billing.mdx
Resumes a subscription after cancellation by subscribing the customer back to their current paid plan.
```typescript
await paykit.subscribe({
customerId: "user_123",
planId: "pro", // resume: clears the scheduled downgrade
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/stripe.mdx
Configure Stripe for PayKit, set up webhooks, sync products, and use the customer portal.
```typescript
import {
stripe
} from "@paykitjs/stripe";
import { createPayKit } from "paykitjs";
export const paykit = createPayKit({
// ...
provider: stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
}),
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/stripe.mdx
Configure Stripe for PayKit, set up webhooks, sync products, and use the customer portal.
```typescript
export const paykit = createPayKit({
// ...
testing: {
enabled: true,
},
});
```
--------------------------------
### paykit.ts
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/stripe.mdx
Configure Stripe for PayKit, set up webhooks, sync products, and use the customer portal.
```typescript
export const paykit = createPayKit({
// ...
provider: stripe({
secretKey: process.env.STRIPE_SECRET_KEY!,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
apiVersion: "2026-03-04.preview",
}),
});
```
--------------------------------
### Practical pattern for checking and reporting usage
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/entitlements.mdx
A pattern to check entitlements before acting and report usage only after the action succeeds.
```typescript
export async function POST(request: Request) {
const { allowed } = await paykit.check({
customerId: userId,
featureId: "messages",
});
if (!allowed) {
return Response.json({ error: "Usage limit reached" }, { status: 403 });
}
const response = await generateChatResponse(input);
await paykit.report({
customerId: userId,
featureId: "messages",
amount: 1,
});
return Response.json(response);
}
```
--------------------------------
### Client
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/polar.mdx
Redirect the user to the customer portal from the client.
```typescript
const { url } = await paykitClient.customerPortal({
returnUrl: window.location.href,
});
window.location.href = url;
```
--------------------------------
### Inferring plan and feature IDs
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/concepts/typescript.mdx
Shows how to use the `$infer` helper to expose inferred union types for plan and feature IDs.
```typescript
type PlanId = typeof paykit.$infer.planId;
// => "free" | "pro" | "ultra"
type FeatureId = typeof paykit.$infer.featureId;
// => "messages" | "pro_models" | "priority_support"
```
--------------------------------
### Listen to Billing Changes
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/flows/subscription-billing.mdx
Adds event handlers to the PayKit instance to react to billing changes, such as customer subscription updates.
```typescript
export const paykit = createPayKit({
// ...
on: {
"customer.updated": ({ payload }) => {
console.log("billing changed for", payload.customerId);
console.log("subscriptions:", payload.subscriptions);
// sync to your own data layer, invalidate caches, etc.
},
},
});
```
--------------------------------
### Register event handlers
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/handle-webhooks.mdx
Register event handlers for PayKit events.
```typescript
const paykit = createPayKit({
// ...
on: {
"payment_method.attached": async ({ customer }) => {
await markBillingReady(customer.referenceId);
},
"charge.failed": async ({ customer, error }) => {
await notifyBillingFailure(customer.referenceId, error);
},
},
});
```
--------------------------------
### Changesets Command
Source: https://github.com/getpaykit/paykit/blob/main/CONTRIBUTING.md
Command to generate a changeset file after making changes to packages.
```bash
pnpm changeset
```
--------------------------------
### Sandbox mode
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/providers/polar.mdx
Configure the Polar adapter to use the sandbox environment.
```typescript
provider: polar({
accessToken: process.env.POLAR_ACCESS_TOKEN!,
webhookSecret: process.env.POLAR_WEBHOOK_SECRET!,
server: "sandbox",
}),
```
--------------------------------
### Load the customer's methods
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/charge-a-saved-payment-method.mdx
Retrieves a list of saved payment methods for a given customer and provider.
```typescript
const methods = await paykit.paymentMethod.list({
providerId: "stripe",
customerId: "cust_abc",
});
```
--------------------------------
### PayKitProvider Interface
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/drafts/docs-guides/create-a-custom-provider.mdx
The interface that custom providers must implement to adhere to the PayKit contract.
```typescript
interface PayKitProvider {
id: string;
upsertCustomer(...): Promise<{ providerCustomerId: string }>;
checkout(...): Promise<{ url: string }>;
attachPaymentMethod(...): Promise<{ url: string }>;
detachPaymentMethod(...): Promise;
charge(...): Promise;
refund(...): Promise;
handleWebhook(...): Promise;
}
```
--------------------------------
### Check Feature Usage
Source: https://github.com/getpaykit/paykit/blob/main/apps/web/content/docs/flows/subscription-billing.mdx
Checks if a customer can use a specific feature, like pro models. Also demonstrates checking boolean features.
```typescript
return Response.json({ error: "Usage limit reached" }, { status: 403 });
}
// also check boolean features:
const { allowed: canUseProModels } = await paykit.check({
customerId: userId,
featureId: "pro_models",
});
```