@creem_io/better-auth
v2.0.4
Published
Creem official Better-Auth plugin
Readme
@creem_io/better-auth
Connect Creem billing to a Better Auth application.
The plugin adds session-aware checkout, customer portal, subscription, and transaction endpoints. Verified webhooks can keep subscription state in your Better Auth database and run your own access provisioning callbacks.
Full documentation: docs.creem.io/code/sdks/better-auth
| I want to… | Go to | | ---------------------------------------------- | --------------------------------------------------------------------------- | | Add the plugin to an application | Quickstart | | Configure persistence and the database schema | Configuration | | Use checkout, portal, and subscription methods | Client API | | Synchronize billing and provision access | Webhooks and access | | Call Creem from trusted server code | Server API |
Install
pnpm add @creem_io/better-auth better-auth@^1.5.6The plugin supports Better Auth ^1.5.6 and Zod 3 or 4. Native endpoint inference requires
Better Auth 1.5.6 or later within 1.x. The Creem TypeScript SDK is included.
Minimal setup
Register the server plugin:
// lib/auth.ts
import { creem } from "@creem_io/better-auth";
import { betterAuth } from "better-auth";
export const auth = betterAuth({
database: {
// Your Better Auth database configuration
},
plugins: [
creem({
apiKey: process.env.CREEM_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
testMode: true,
defaultSuccessUrl: "/billing/success",
persistSubscriptions: true,
}),
],
});Register the client plugin:
// lib/auth-client.ts
import { creemClient } from "@creem_io/better-auth/client";
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
plugins: [creemClient()],
});The client plugin infers endpoint inputs, successful responses, and Creem session fields through Better Auth.
The createCreemAuthClient wrapper remains exported for compatibility but is deprecated.
If the server disables persistence, also use creemClient({ persistSubscriptions: false }) so
session types reflect the absence of Creem user fields. Failed client calls return data: null
and an error with message and status; direct auth.api calls throw APIError.
Upgrading from 1.x? Follow the 2.0 migration guide for redirect defaults, error handling, schema configuration, and cancellation changes.
When persistence is enabled, apply the plugin schema directly with Better Auth's built-in Kysely adapter:
npx @better-auth/cli migrateFor Prisma, Drizzle, or another ORM-managed schema, run npx @better-auth/cli generate and apply
the result with the ORM's migration tooling.
Create a checkout for the signed-in user:
const { data, error } = await authClient.creem.createCheckout({
productId: "prod_...",
successUrl: "/billing/success",
});
if (!error && data?.url) {
window.location.assign(data.url);
}Checkout and portal navigation is manual by default (redirect: false). Pass
redirect: true to either method to let Better Auth navigate automatically.
Finally, register this URL as a webhook in the Creem dashboard:
https://your-domain.com/api/auth/creem/webhookThe route is available only when webhookSecret is configured. /api/auth is Better Auth's
default base path.
Client methods
createCheckout(input)createPortal(input?)cancelSubscription(input)retrieveSubscription(input)searchTransactions(input?)hasAccessGranted()
See the client API documentation for inputs, results, and authorization notes.
Examples and development
From the repository root:
pnpm --filter @creem_io/better-auth build
pnpm --filter @creem_io/better-auth test
pnpm --filter @creem_io/better-auth typecheck
pnpm --filter @creem_io/better-auth check:package