Skip to main content
This guide is the complete setup sequence in one page, with validation steps — optimized for AI agents and for careful step-by-step integration (agents can fetch it as markdown by appending .md to this page’s URL). For learning the component and ongoing development, start with the Quickstart and its sibling pages.
This guide walks through a complete Convex Creem integration for React or Svelte. Use this order:
  1. Set up the Convex component and webhook route.
  2. Export the connected Convex billing API.
  3. Define the browser-side billing catalog.
  4. Wrap your billing UI in CreemConvexProvider.
  5. Choose the billing path you need: subscriptions, one-time products, credits, account tools, or usage gates.
For brownfield projects, first inventory the billing integration you are replacing. Agent automation can add the Convex Creem component, routes, and catalog wiring, but it cannot know which old provider settings are still safe to remove from your deployment or payment dashboard. Before switching traffic, check:
  • Existing webhook paths in your app and payment provider dashboard, such as /api/stripe/webhook, /api/billing/webhook, /webhooks/lemonsqueezy, or other custom billing endpoints. Keep them only if another live billing flow still depends on them.
  • Public client env vars for the old billing UI, such as product, price, plan, checkout, or publishable-key variables in VITE_*, NEXT_PUBLIC_*, or PUBLIC_* namespaces.
  • Server env vars for the old billing system, such as API keys, webhook signing secrets, customer portal configuration, price IDs used by server actions, or framework route secrets.
  • Background jobs, scheduled syncs, or server functions that still read the old billing env vars or process the old webhook events.
Clean up the old webhook registrations and env vars manually after confirming the Convex Creem webhook is receiving events and any necessary historical data has been migrated or retained. Do not delete old secrets before rollback and data-retention requirements are clear.

1. Install

Install the package plus the peer dependencies for the frontend framework you use.
For Svelte widgets:
For React widgets:

2. Register the Convex component

Create or update convex/convex.config.ts:
Set Creem secrets in Convex:
CREEM_SERVER=test points the component at the Creem test API, matching a test-mode API key. Set it to prod (or omit it) when deploying with a production key. If you use credit packs, also set a server-side product ID. Do not trust a browser-exposed product ID for webhook fulfillment:

3. Export the Convex billing API

Create convex/billing.ts. Replace the resolver with your real auth and entity logic. entityId is the billing owner; use the user ID for user billing or the org/team ID for organization billing.
Security boundary:
  • export const creem = new Creem(...) exports a normal server-side object for other Convex modules such as http.ts; it does not register a client-callable Convex function.
  • Functions returned by creem.api({ resolve }) become public when exported from convex/billing.ts.
  • resolve must authenticate the caller and authorize the selected user or organization. Generated functions then bind customers, subscriptions, transactions, and credit reads to that resolved entityId.
  • Privileged credit operations are intentionally absent from the generated public API. Put grants and spending behind app-owned actions whose amount, reference, and idempotency policy are controlled on the server.
What to consider:
  • Export only capabilities your UI needs. If you omit subscriptions.cancel, cancel buttons disappear.
  • Use cancelMode: "scheduled" when canceling should keep access until the current period ends. Use "immediate" when cancellation should end access immediately.
  • Put credit grants in the server catalog because webhooks run on the server.
  • syncBillingProducts is intentionally an internalAction. Trigger it from the Convex CLI, dashboard, or another trusted internal function, not from browser UI.
  • App-owned credit spending, such as generateImage, should call creem.credits.debitForEntity with server-controlled business inputs. The credits widget only displays and refreshes balance state.

4. Register the webhook route

Create or update convex/http.ts:
In Creem, set the webhook endpoint to:
The component stores customers, subscriptions, orders, refunds, disputes, and credit grants from supported Creem events.

Create the products

Every plan in your catalog maps to a Creem product. Create them in the dashboard, or with the CLI. Running it through npx avoids installing anything globally on the developer’s machine:
Use the same Creem API key you set as CREEM_API_KEY in step 2. brew and global npm installs are also available; see the CLI guide. Repeat for every plan and billing cycle you offer. A plan billed monthly and yearly needs two products. creem products list --json prints the IDs for scripting. --billing-period accepts every-month, every-three-months, every-six-months, or every-year, and is required when --billing-type is recurring. Use --billing-type onetime for one-time products and credit packs.

Sync them into Convex

Once the products exist, pull their metadata into Convex:
This works with the internal action above. If you expose your own admin-only public action instead, protect it server-side and keep it out of client-facing billing pages.

5. Add CSS

Import the package CSS in your app CSS entry point:

6. Define the browser billing catalog

Create a shared catalog file in your frontend. Import from the framework entry you are using (/svelte or /react).
What to consider:
  • creemProductIds maps billing cycles to Creem product IDs.
  • Supported recurring cycles are every-month, every-three-months, every-six-months, and every-year.
  • If a plan has multiple cycles, the interval selector appears automatically.
  • Product IDs used only by frontend widgets may live in your framework’s public client env namespace, such as Vite VITE_*, Next.js NEXT_PUBLIC_*, or SvelteKit PUBLIC_*. Trusted webhook fulfillment data must live in Convex env vars.

7. Connect Svelte

In Svelte, initialize Convex once with setupConvex, create a ConnectedBillingApi, and wrap widgets in CreemConvexProvider. The provider is the required integration boundary. ConvexCreemProvider is not an exported component name; the package exports CreemConvexProvider.
Important: connected widgets must be rendered inside CreemConvexProvider. Do not pass api={...} directly to Subscription.Root, Product.Root, BillingPortal, or BillingHistory. The provider-level ConnectedBillingApi decides which paths are available: Use createCreemSvelte when you want one typed binding object:
You can also read uiModel directly once for account-level UI such as payment recovery and usage gates:

8. Connect React

React uses the same ConnectedBillingApi shape. The difference is your normal Convex React client setup.

9. Choose your billing path

Use the closest path as your starting point. The external paths are:
  • /creem/events — Convex HTTP webhook endpoint for Creem.
  • Creem checkout URL — opened by checkouts.create.
  • Creem customer portal URL — opened by customers.portalUrl.
  • Your checkout success URL — defaults to the current page path when successUrl is not passed.
Detailed feature guides: Subscriptions, One-Time Products & Credits, Entitlements & Account UI, Advanced.

10. Environment placement checklist

Use your app framework’s public client env namespace only for values the browser needs to render widgets or start checkout, such as product IDs referenced by the frontend catalog:
Trusted server values are set with Convex, not in .env files:
In brownfield projects, also remove stale billing env vars after the migration is verified. Old provider values usually live in several places: local .env* files, hosting provider env settings, CI secrets, Convex env, and the payment provider dashboard. Search for the old provider name and old public prefixes so unused webhook secrets, price IDs, product IDs, publishable keys, and API keys do not linger.

11. Validation

Before shipping an integration:
  • Type-check and lint your app with your project’s usual commands.
  • Run timeout 30 npx convex dev --once and confirm the deployment pushes without errors.
  • Complete a test-mode checkout with a test card and confirm the webhook writes billing state (check the Convex dashboard data browser and logs).
  • Confirm the widgets reflect the new subscription without a page reload.