@creem_io/better-auth integration. For a new
integration, start with the quickstart.
Upgrading from 1.x
Version 2.0 changes checkout navigation and endpoint error handling, improves native client types, and distinguishes scheduled cancellation from final cancellation in webhook callbacks and persisted access checks. Review the client, server, and webhook changes below before deploying. No database schema migration is required for unchanged default persistence settings. If you use custom schema mappings, review the mapping changes below against your existing database.Upgrade Better Auth alongside the plugin
Version 2.0 requires Better Auth^1.5.6. The native inferred endpoint declarations depend on
Better Auth types that are not available at the previous minimum of 1.3.34. Upgrade both packages
together, including in separate server and client applications:
Update checkout and portal navigation
Checkout and portal methods now default toredirect: false. Existing calls that relied on
automatic navigation must explicitly opt in:
redirect or set it to false, handle error, and navigate using
data.url:
Migrate to the native client
createCreemAuthClient is deprecated but remains exported. Replace it with the standard Better Auth
client for your framework and keep the Creem client plugin:
session.user.creemCustomerId and session.user.hadTrial when persistence is enabled. Error
payloads no longer appear as alternatives inside the successful data type, so checks such as
"url" in data are unnecessary after handling error.
Native types follow the endpoint’s actual SDK response. Customer or product values can be IDs or
expanded objects; narrow them before reading properties. Date values received over HTTP are
serialized, not JavaScript Date instances. For example:
Update transaction response paths
The Better AuthsearchTransactions() endpoint now returns the transaction page directly as
{ items, pagination }, matching the documented client contract. If you previously used the native
client or raw endpoint’s SDK iterator envelope, change data.result.items to data.items and
data.result.pagination to data.pagination. The HTTP endpoint does not expose iterator methods.
The standalone helper from @creem_io/better-auth/server is unchanged.
Update endpoint error handling
Failures fromcreateCheckout, createPortal, cancelSubscription, retrieveSubscription,
searchTransactions, and hasAccessGranted now use Better Auth’s APIError mechanism. Existing
HTTP status codes are preserved, but the error contract changes:
Do not check
data.error or assume a failed direct server call resolves to an error object.
hasAccessGranted() returns data.hasAccessGranted as a boolean on success. Signed-out requests (401), disabled persistence
(400), and failed checks (500) use the error path with data: null instead of an indeterminate
access result. Treat an error as a failed check, not authorization.
See the Server API for a
try/catch example. Helpers imported from @creem_io/better-auth/server are separate from these
Better Auth endpoints and retain their own behavior.
Match persistence configuration and review schema mappings
The full persistence opt-out remains supported. A server configured withpersistSubscriptions: false registers neither subscription models nor Creem user fields and
performs no plugin customer, trial, or subscription writes. Mirror that setting in the client so
its session types match the server:
schema option now correctly types physical name mappings for existing plugin models and
fields. Field overrides are column-name strings, not Better Auth field definition objects:
Cancellation and access changes
Access behavior in this table refers to
hasAccessGranted() with persistence enabled. The
existing past_due and unpaid period-end grace behavior is unchanged. The direct
server helpers retain their documented active-status scope.
Update your callbacks
Addsubscription_canceled to any exhaustive switches or mappings over RevokeAccessReason or
AccessChangeReason. If your onRevokeAccess handler already handles every reason the same way,
it will now also run for final cancellation.
If you currently revoke access in onSubscriptionCanceled, move that logic into
onRevokeAccess, or ensure that calling both handlers has the same effect as calling one.
Keep handlers idempotent because webhooks can be delivered more than once. These callback
changes also apply when persistSubscriptions: false.
Scheduling cancellation does not invoke onGrantAccess or onRevokeAccess. If you manage
entitlements outside the plugin database, use onSubscriptionScheduledCancel to store the
period end and enforce it in your own access checks. See
Webhooks and access for callback examples and retry behavior.
Review existing records and entitlements
The new access policy applies to existing records as soon as you deploy 2.0. Upgrading does not replay webhooks or invokeonRevokeAccess for records already stored as canceled.
Before deploying:
- Review local canceled records that currently grant access and compare them with the subscription’s current state in Creem. Correct stale local state from that source; do not relabel a canceled subscription as scheduled solely because its stored period end is in the future.
- If you store entitlements separately, reconcile them with the current subscription state. Do not rely on a new revoke callback arriving solely because you upgraded the package.
- Check any custom use of
cancelAtPeriodEnd. Existing flags are not automatically backfilled; subsequent subscription webhooks and checkout writes synchronize the flag. The plugin’s access checks usestatusandperiodEnd.
An existing canceled record can still have a future
periodEnd. In this edge case, upgrading
stops that record from granting access immediately, rather than waiting for the stored date.Install and verify
After updating your handlers and reviewing existing state, install the new major version:auth.api error handling. In test
mode, verify that scheduled cancellation preserves access before the period end, that access
ends at the period boundary, and that final cancellation invokes your revoke logic without
duplicate side effects. If you manage entitlements separately, verify those access checks too.