> ## 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.

# Client API

> Create checkouts, open the billing portal, and manage Creem subscriptions through Better Auth.

The client plugin exposes billing methods under `authClient.creem`. Requests include the current
Better Auth session when one is available. Portal, subscription, transaction, and access endpoints
require a signed-in user; checkout can also be created without a session.

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

export const authClient = createAuthClient({
  plugins: [creemClient()],
});
```

The plugin infers endpoint inputs, successful responses, and Creem session fields through Better Auth. The
`createCreemAuthClient` wrapper remains exported for compatibility but is deprecated.

Every method returns the Better Auth `{ data, error }` result shape. Handle `error` before using
`data`. A failed request returns `data: null` and an error containing `message`, `status`, and
`statusText`; successful response types do not contain an error alternative.

```typescript theme={null}
const { data, error } = await authClient.creem.createPortal();

if (error) {
  console.error(error.status, error.message);
} else if (data.url) {
  window.location.assign(data.url);
}
```

Creem session fields are inferred when persistence is enabled. If the server uses
`persistSubscriptions: false`, configure `creemClient({ persistSubscriptions: false })` too.
The client option controls inference; it does not change the server configuration.

## Create a checkout

Navigation is manual by default (`redirect: false`). Set `redirect: true` to let Better Auth
redirect to the checkout URL automatically.

```typescript theme={null}
const { data, error } = await authClient.creem.createCheckout({
  productId: "prod_...",
  units: 1,
  successUrl: "/billing/success",
  discountCode: "LAUNCH20",
  metadata: { plan: "pro" },
});

if (!error && data?.url) {
  window.location.assign(data.url);
}
```

| Input | Required | Description |
| - | - | - |
| `productId` | Yes | Product to purchase. |
| `requestId` | No | Idempotency key for retrying checkout creation. |
| `units` | No | Positive unit count; defaults to `1`. |
| `discountCode` | No | Active Creem discount code. |
| `customer.email` | No | Defaults to the signed-in user's email. |
| `customFields` | No | Up to three text or checkbox fields shown during checkout. |
| `successUrl` | No | Overrides `defaultSuccessUrl` for this checkout. |
| `redirect` | No | Redirect automatically when `true`; defaults to `false`. |
| `metadata` | No | Application metadata. The signed-in user ID is added as `referenceId`. |

<Note>
  `customField` is a deprecated alias for `customFields`. New code should use `customFields`.
</Note>

## Open the customer portal

```typescript theme={null}
const { data, error } = await authClient.creem.createPortal();

if (!error && data?.url) {
  window.location.assign(data.url);
}
```

To redirect automatically, use `await authClient.creem.createPortal({ redirect: true })`.
The default is `redirect: false`, which returns the URL for manual navigation.

With persistence enabled, omit `customerId` so the plugin uses the current user's stored
`creemCustomerId`. The endpoint also accepts an explicit customer ID, but it does not verify that
the ID belongs to the signed-in user. Do not pass a value obtained from untrusted client input.

## Check access

`hasAccessGranted()` reads the signed-in user's persisted subscriptions. It grants access for
`active`, `trialing`, or `paid` records. A `scheduled_cancel`, `past_due`, or `unpaid` subscription also
retains access while its `periodEnd` is still in the future, so customers can use time they have
already paid for. A `canceled` subscription no longer grants access.

```typescript theme={null}
const { data, error } = await authClient.creem.hasAccessGranted();

if (!error && data?.hasAccessGranted) {
  console.log("Access granted", data.subscription);
}
```

On success, `data.hasAccessGranted` is a boolean. A signed-out request returns an error with status
`401`, disabled persistence returns `400`, and a failed database check returns `500`. These failures
return `data: null`, so check `error` before reading the access result. Do not grant access when the
check fails.

## Cancel a subscription

```typescript theme={null}
const { data, error } = await authClient.creem.cancelSubscription({
  id: "sub_...",
});
```

The published client type requires the subscription ID. The endpoint does not consistently verify
ownership of caller-supplied IDs, so derive the ID from billing state already authorized for the
signed-in user. Use the returned `success` and `message` fields to update the interface.

## Retrieve a subscription

```typescript theme={null}
const { data, error } = await authClient.creem.retrieveSubscription({
  id: "sub_...",
});
```

The result includes the subscription status, customer, product, billing dates, and metadata.
Customer and product values can be IDs or expanded objects; narrow their types before reading
object properties. Dates returned over HTTP are serialized values, so convert them with `new Date()`
when you need date methods instead of assuming a JavaScript `Date` instance.
As with cancellation, do not accept the subscription ID from an untrusted caller without checking
that it belongs to the signed-in account.

## Search transactions

```typescript theme={null}
const { data, error } = await authClient.creem.searchTransactions({
  productId: "prod_...",
  pageNumber: 1,
  pageSize: 20,
});

for (const transaction of data?.items ?? []) {
  console.log(transaction.id, transaction.status, transaction.amount);
}
```

The response contains `data.items` and `data.pagination`; it does not expose the SDK page iterator.

Available filters are `customerId`, `productId`, `orderId`, `pageNumber`, and `pageSize`. When
`customerId` is omitted, the endpoint uses the customer associated with the signed-in user. Prefer
that default: an explicit customer ID is not checked against the current user.

## Type exports

Client input and result types can be imported from the package root or client entry point:

```typescript theme={null}
import type {
  CancelSubscriptionInput,
  CreateCheckoutInput,
  CreatePortalInput,
  HasAccessGrantedResponse,
  RetrieveSubscriptionInput,
  SearchTransactionsInput,
} from "@creem_io/better-auth";
```


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