Summary: Subscription billing runs through Chargebee, with completely separate configurations (namespaces and API keys) for the 7Mind and 7Sleep products, managed by the monetization domain in elixir-backend.
Sources: direct code inspection (config/runtime/prod.ex, lib/backend/monetization/, mix.exs — ex_chargebee 0.3.1)
Last updated: 2026-05-15
Setup
Chargebee is the primary subscription and billing provider. The backend uses the ex_chargebee Elixir library (v0.3.1).
Two completely separate Chargebee accounts (namespaces) exist — one per brand:
| Brand | Env var |
|---|---|
| 7Mind | SEVENMIND_CHARGEBEE_NAMESPACE, SEVENMIND_CHARGEBEE_API_KEY |
| 7Sleep | SLEEP_CHARGEBEE_NAMESPACE, SLEEP_CHARGEBEE_API_KEY |
A “namespace” in Chargebee is the subdomain of the API endpoint (e.g., sevenmind.chargebee.com). Having separate namespaces means subscriptions, customers, plans, and billing events are fully isolated between brands at the Chargebee level.
Legacy providers
The monetization domain also integrates with:
- Fastspring — legacy billing system, now only accessible via admin panel (
FASTSPRING_ADMIN_PANEL) - Barmer — German health insurer integration (likely B2B2C provisioning)
- Mondia — carrier billing integration
Coupon and gift flows
Based on domain naming in the CLAUDE.md documentation, the monetization domain handles coupons, trials, and gifts in addition to standard subscriptions.
ZPP / Prevention relationship
Insurance-related billing (ZPP certificates for German health insurance reimbursement) is handled by the prevention domain, not monetization. The two domains are separate. Prevention owns the PDF certificate generation and Cloud Storage upload; monetization owns the payment collection.
What agents should know
- Always confirm which brand’s Chargebee account a change targets. The env vars and configurations are parallel, not shared.
- Webhook events from Chargebee arrive as external events and should be processed through the event bus pattern — do not add direct Chargebee webhook handlers outside the
monetizationdomain. - Fastspring is legacy. No new integrations should be built against it.
- The
monetizationdomain has its own database (BACKEND_MONETIZATION_DATABASE_URL). Subscription state lives there, not in the user identity database.
From 7mind-mobile-apps-monorepo
The Flutter app uses the official chargebee_flutter 0.4.8 SDK to interact with Chargebee directly from the device (subscription state, checkout, restoration). Server-side, elixir-backend uses the Elixir ex_chargebee 0.3.1 library. The two halves communicate through Chargebee, not directly:
- Mobile collects payment and initiates the subscription via Chargebee SDK
- Chargebee fires webhooks to the backend; the
monetizationdomain processes them through the event bus pattern - Subscription state on the device should not be trusted as authoritative; always confirm against the backend on launch
The Flutter monorepo ships only the 7Mind brand, so it only carries the SevenMind Chargebee config — there is no 7Sleep flavor in this codebase (see dual-brand-routing for the brand split).
From nuxt-website
The web frontend integrates Chargebee via the chargebee npm package and a custom ChargebeeDialog.vue checkout component. Per-brand configuration is exposed at runtime through:
NUXT_ENV_CHARGEBEE_ID— the Chargebee site (namespace) the JS client opens. Prod:7mind(7mind brand) /7sleep(7sleep brand). Staging:7mind-test/7sleep-test.NUXT_ENV_CHARGEBEE_API_KEYandNUXT_ENV_CHARGEBEE_API_KEY_7SLEEP_{LIVE,STAGING}— API keys used by checkout flows.
The web does not talk to the backend’s ex_chargebee directly. Instead it (a) opens the hosted Chargebee checkout via the JS SDK and (b) calls backend API routes for portal sessions and gift/coupon flows. Relevant backend endpoints (from config/routes.js):
POST /monetization/chargebee/self_serve_portal/session— creates the Chargebee customer portal session for the logged-in userPOST /monetization/coupon/resolve— coupon validationPOST /monetization/gift/claim— gift redemptionGET /monetization/subscriptions/status— subscription state probe
Legacy Fastspring is still surfaced via NUXT_ENV_FASTSPRING_STOREFRONT and pages/payments.vue; new checkout work goes to Chargebee.
Related
- dual-brand-routing — why there are two Chargebee namespaces instead of one
- modulith-domain-model — monetization is a domain with its own isolated database
- supertokens-auth — user identity is separate from subscription state
- elixir-backend — the repo this lives in
- 7mind-mobile-apps-monorepo — the mobile client that integrates Chargebee SDK on-device
- nuxt-website — web client that opens Chargebee checkout and calls backend portal/coupon/gift endpoints