@kerne/server is the only place that should ever hold your secret key. It’s what lets a request act on behalf of any customer, not just the caller - that’s the whole reason it stays server-side.
Install & configure
The surface, by tier
The methods are grouped by who is meant to call them - not by resource - because that’s what actually changes as you build:1
Tier 1 - entitlements, flat on the client
The reason this SDK exists. No
.billing. prefix - these are the calls you’ll write the most.customer is required on reportUsage() / reportUsageBatch(). On allows() / enforce() / check() / consume() it is optional in the types, but with a secret key there is no implicit “current user” - pass the customer you mean. See Entitlements & usage.2
Tier 2 - billing the end user touches
3
Tier 3 - identity & growth
Customers
The billable identity every call above names ascustomer. A signed-up Kerne user already has one - external_id is set to their User.id at signup, so you never call this yourself just to use the SDK.
Reach for kerne.customers when you run your own auth (Clerk, Supabase, your own backend) and want to keep email/name in sync with your system of record ahead of the customer’s first billing action, or when you bill an organization rather than a person and want to look it up later by the id you gave it:
get, list and update return the customer’s metadata exactly as you last wrote it, plus provider_accounts - the provider customer this one maps to on each connected payment account ([{ provider, provider_customer_id }]). That list stays empty until their first checkout, which is what creates the provider customer.
Admin-only (secret key) - not exposed in @kerne/react, since a signed-in end user’s own customer is always resolved from their session, never named explicitly.
Next.js (App Router)
There is no Next-specific adapter -@kerne/server is the same client in a Route Handler or a Server Action. Take the customer id from your own session/user record and pass it explicitly:
@kerne/server/next instead of @kerne/server gives you the identical surface plus an import 'server-only' guard, so a bundler pulling the module into a Client Component fails at build time rather than shipping the secret key to the browser.
Escape hatch
If a route you need isn’t wrapped yet,kerne.request() calls it directly with the same authentication as everything else - see Direct requests.
What this SDK does not do
Catalog management (products, plans, prices, packs) isn’t in this SDK - that’s control-plane configuration for your own dashboard, not something your app’s backend does at runtime. Use the Kerne dashboard or@kerne/contracts for that.
