> ## Documentation Index
> Fetch the complete documentation index at: https://docs.creem.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> Configure the Creem Better Auth server and client plugins, persistence, and database schema.

## Server options

Pass these options to `creem()` in your Better Auth configuration:

| Option | Type | Default | Description |
| - | - | - | - |
| `apiKey` | `string` | Required | Creem API key for the selected environment. Keep it on the server. |
| `webhookSecret` | `string` | — | Signing secret used to verify Creem webhooks. The webhook endpoint is omitted when this is not set. |
| `testMode` | `boolean` | `false` | Uses `https://test-api.creem.io` instead of the production API. |
| `defaultSuccessUrl` | `string` | — | Checkout return URL used when a request does not provide `successUrl`. Relative and absolute URLs are supported. |
| `persistSubscriptions` | `boolean` | `true` | Adds the plugin schema and synchronizes customer and subscription data from webhooks. |
| `schema` | `CreemSchemaOverrides` | — | Physical model and column name overrides for existing plugin fields. |

Webhook callback options are covered in [Webhooks and access](/code/sdks/better-auth/webhooks).

```typescript lib/auth.ts theme={null}
import { creem } from "@creem_io/better-auth";
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  database: {
    // Your database configuration
  },
  plugins: [
    creem({
      apiKey: process.env.CREEM_API_KEY!,
      webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
      testMode: process.env.NODE_ENV !== "production",
      defaultSuccessUrl: "/billing/success",
      persistSubscriptions: true,
    }),
  ],
});
```

<Warning>
  `testMode` defaults to `false`. Do not pair a test API key with production mode or a production
  API key with test mode.
</Warning>

## Persistence mode

Persistence is enabled unless you explicitly set `persistSubscriptions: false`. The plugin then:

* adds its models and fields to the Better Auth schema;
* associates a Creem customer ID with the signed-in user;
* writes subscription state received through verified webhooks;
* checks local subscription records in `hasAccessGranted()`;
* records whether a user has already received a trial.

After enabling persistence or upgrading to a version that changes the schema, use the command for
your database workflow. The built-in Kysely adapter can apply the migration directly:

```bash theme={null}
npx @better-auth/cli migrate
```

For Prisma, Drizzle, or another ORM-managed schema, generate the schema and then apply it with the
ORM's migration tooling:

```bash theme={null}
npx @better-auth/cli generate
```

### Added models and fields

The `creem_subscription` model contains:

| Field | Type | Notes |
| - | - | - |
| `productId` | string | Creem product ID |
| `referenceId` | string | Better Auth user ID or another application reference |
| `creemCustomerId` | string, optional | Creem customer ID |
| `creemSubscriptionId` | string, optional | Creem subscription ID |
| `creemOrderId` | string, optional | Creem order ID |
| `status` | string | Defaults to `pending` |
| `periodStart` | date, optional | Current billing period start |
| `periodEnd` | date, optional | Current billing period end |
| `cancelAtPeriodEnd` | boolean, optional | Synchronized from status by subscription webhooks and checkout writes: `true` for `scheduled_cancel`, otherwise `false` |

Existing records are not automatically backfilled. `cancelAtPeriodEnd` may remain unset or stale
until a subsequent event updates the record. Access checks use `status` and `periodEnd`.

The plugin extends the Better Auth `user` model with:

| Field | Type | Notes |
| - | - | - |
| `creemCustomerId` | string, optional | Customer used for portal and customer-scoped requests |
| `hadTrial` | boolean, optional | Defaults to `false`; set after the user enters a trial |

### Without persistence

Set `persistSubscriptions: false` when your application owns subscription storage or does not need
local billing state:

```typescript theme={null}
creem({
  apiKey: process.env.CREEM_API_KEY!,
  webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
  persistSubscriptions: false,
});
```

No plugin schema is added: neither subscription models nor Creem user fields are registered.
No plugin customer, trial, or subscription data is written. `hasAccessGranted()` cannot
determine access in this mode, so implement access checks in your own data layer. Other endpoints
can still call Creem, provided they receive or can resolve the required customer or subscription
identifier.

Mirror this option in your client configuration so session types do not promise fields that the
server has not registered:

```typescript theme={null}
const authClient = createAuthClient({
  plugins: [creemClient({ persistSubscriptions: false })],
});
```

### Custom model and column names

With persistence enabled, `schema` maps existing logical names to physical database names:

```typescript theme={null}
creem({
  apiKey: process.env.CREEM_API_KEY!,
  schema: {
    creem_subscription: {
      modelName: "billing_subscription",
      fields: { referenceId: "user_id" },
    },
    user: {
      fields: { creemCustomerId: "creem_customer_id" },
    },
  },
});
```

Field mappings are strings, not field definition objects. They rename existing models and columns;
they do not add models, add fields, or change their types. The logical names in session and endpoint
types stay the same. Overrides are ignored when persistence is disabled. Each server plugin instance
has its own schema, so overrides do not affect other instances.

## Client options

The standard Better Auth client infers the Creem endpoints from `creemClient()`:

```typescript lib/auth-client.ts theme={null}
import { creemClient } from "@creem_io/better-auth/client";
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_APP_URL,
  plugins: [creemClient()],
});
```

`baseURL` is optional when the client calls the same origin. Use Better Auth's client import for
your framework, such as `better-auth/react` for React.

The standard client infers Creem endpoint inputs and successful responses. With persistence enabled
(the default), it also infers `session.user.creemCustomerId` and `session.user.hadTrial`. The client
option `persistSubscriptions` must match the server option; it controls types only and cannot enable
server persistence.

`createCreemAuthClient` remains exported but is deprecated. Replace it with your framework's standard
`createAuthClient` while keeping `creemClient()` in the plugins array. See the
[2.0 migration guide](/code/sdks/better-auth/migration) for response handling changes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.