{"id":"plans-billing","type":"module","title":"Plans, Billing and Entitlements","status":"ga","audience":["org-admin","prospect","finance"],"scope":"both","tier_min":"free","aliases":["15b","pricing","subscription","entitlements"],"summary":"How an org pays for Klarum and what each tier is entitled to: a four-tier ladder with Free as the floor, a per-seat Business tier, enforced monthly meters on Free inference spend, and the trial between them.","keywords":["tiers","stripe","meters","trial","seats","capabilities","checkout","entitlements"],"body":{"what_it_is":"How a firm pays for Klarum, and what each tier is entitled to. This module\nexists because the commercial model is the one part of the product a prospect\nmeets **before** anything else in this catalogue, and it was previously\ndocumented nowhere - which left the marketing site asserting a plan ladder no\nsource of truth carried (issue #1928).\n\nFour tiers, low to high: **Free**, **Basic**, **Business**, **Enterprise**\n(`feature_matrix.TIER_ORDER`). Prices are SEK, live on Klarum's Stripe\naccount, and every `lookup_key` round-trips through one shared table so the\nwebhook sync and the price resolver cannot disagree about what a price\nmeans.\n\n| Tier | `lookup_key` | Price | Notes |\n|---|---|---|---|\n| Free | `free` | 0 SEK/month | A real 0 SEK Stripe subscription, not the absence of one |\n| Basic | `basic_month` / `basic_year` | 1 100 SEK/mo, 11 000 SEK/yr | Annual is two months free |\n| Business | `business_month` / `business_year` | 2 000 SEK/seat/mo, 20 000 SEK/seat/yr | Per seat, metered |\n| Enterprise | `enterprise` | 0 SEK/month in Stripe | Negotiated commercially and invoiced outside Stripe; the subscription carries the agreed seat count and an `agreement_ref` |\n\nThere is **no** dedicated billing-settings route: plan and seat chrome\nrenders on the organization settings page, and Checkout lives on its own\nsubscribe surface.\n","what_it_helps_users_do":"Land in the product rather than at a plan picker (Free is provisioned\ndirectly at org creation); try Business for three days without a payment\nmethod; add and remove seats with proration handled by Stripe; and, on Free,\nspend a bounded amount of inference per month with a refusal that does not\nitself burn quota.\n"},"engines":[],"integrations":[],"capabilities":[{"id":"tier-ladder","type":"capability","title":"The tier ladder","summary":"Four tiers low to high, Free, Basic, Business and Enterprise, with every Stripe lookup key round-tripping through one table so the webhook sync and the price resolver cannot disagree.","status":"ga","scope":null,"keywords":["tiers","lookup-key","stripe","sek"],"body":null},{"id":"tier-capabilities","type":"capability","title":"Capabilities per tier","summary":"A capability is binary per tier: engine and exports and connectors from Free, doc generation from Basic, team seats and org settings from Business, and the enterprise block from Enterprise.","status":"ga","scope":null,"keywords":["capability","entitlement","matrix"],"body":{"what_it_is":"A **capability** is binary per tier (`feature_matrix.Capability` /\nthe tier capability matrix).\n\n| Capability | Free | Basic | Business | Enterprise |\n|---|---|---|---|---|\n| `engine` - tender match engine | capped | yes | yes | yes |\n| `exports` - CSV / PDF export | yes | yes | yes | yes |\n| `connectors` - SharePoint / Drive into the capability graph | yes | yes | yes | yes |\n| `doc_gen` - proposal / bid-draft generation | - | yes | yes | yes |\n| `team_seats` - multi-user / invite seats | - | - | yes | yes |\n| `org_settings` - org settings + invitation management | - | - | yes | yes |\n| `sso_scim` - enterprise SSO / SCIM (NOT YET AVAILABLE) | - | - | - | planned |\n| `audit` - audit log + data export | - | - | - | yes |\n| `bespoke_integrations` - per-customer custom integrations | - | - | - | yes |\n| `dedicated_support` - CSM / dedicated support | - | - | - | yes |\n\nNote that `audit` here means the **org-level audit log plus data export**\nsold with Enterprise. It is distinct from the per-workspace\n`workspace_audit_log`, which every tier gets.\n\n**`sso_scim` is not yet available.** It is a reserved entitlement on the\nEnterprise tier, not a shipped capability: there is no SAML, OIDC or SCIM\nimplementation today. It is listed here so the commercial position is\nlegible, and marked `planned` rather than `yes` so nobody reads the row as\na statement that it works. Ask before relying on it for a procurement\nrequirement.\n","what_it_helps_users_do":null}},{"id":"monthly-meters","type":"capability","title":"Meters","summary":"A monthly ceiling on something a tier already holds, enforced by one atomic statement that row-locks the org, resets lazily on a UTC month roll-over and writes nothing once the cap is reached.","status":"ga","scope":null,"keywords":["meter","ceiling","atomic","month-rollover"],"body":{"what_it_is":"A **meter** is a monthly ceiling on something a tier already holds,\nenforced by `tenant_ceiling.consume` - a single atomic statement that\nrow-locks the org, lazily resets on a UTC month roll-over, increments\nwhile under the cap, and writes **nothing** once the cap is reached, so a\nrefusal cannot itself burn quota. State lives at\n`organizations.meta->'meters'->{meter}`. A meter absent from a tier's row\nis unmetered, which keeps the paid hot path off the counter's write path\nentirely.\n\n| Meter | Free cap / month | Paid tiers | What it bounds |\n|---|---|---|---|\n| `match` | 50 | unmetered | Scoring a firm/tender pair |\n| `explain` | 20 | unmetered | LLM-generated narratives: explanations, recommendations, compliance matrices |\n| `enrich` | 5 | unmetered | Cold-start org enrichment, which also bills a third-party search provider per call |\n","what_it_helps_users_do":null}},{"id":"business-trial","type":"capability","title":"The Business trial","summary":"A once-per-org trial of Business with a seven-day window to activate and three full days once activated, requiring no payment method and preserving data when it ends.","status":"ga","scope":null,"keywords":["trial","activation","lapse","no-card"],"body":{"what_it_is":"A once-per-firm trial of Business, offered at signup and **activated by\nthe firm, not automatically**:\n\n- **A 7-day window to activate.**\n  `organizations.meta.trial_offer_expires_at` holds the deadline;\n  `daily_trial_lapse_job` (02:30 UTC, cluster-singleton-guarded) flips\n  still-unactivated offers from `trial_offered` to `trial_lapsed`.\n- **3 full days of Business once activated.** `activate_business_trial`\n  creates a Stripe subscription on `business_month` at the org's current\n  seat count with `trial_end = now + 3 days`.\n- **No payment method required.**\n  `payment_behavior=\"default_incomplete\"` plus\n  `trial_settings.end_behavior.missing_payment_method = \"cancel\"`: the\n  trial simply ends rather than charging anyone.\n- **Data is preserved when it ends.** Lapse and expiry write only\n  `meta.billing_status`; access gates, nothing is deleted.\n- **Once per firm**, guarded by `meta.trial_activated_at`\n  (a second attempt is refused).\n","what_it_helps_users_do":null}},{"id":"seat-billing","type":"capability","title":"Seat billing (Business)","summary":"Per-seat and metered with Stripe authoritative. A seat bills on acceptance, not on invite, with an idempotency key on the invitation id so a retried accept cannot double-bill.","status":"ga","scope":null,"keywords":["seats","proration","idempotency","credit"],"body":{"what_it_is":"Per-seat and metered, with Stripe authoritative. **Bill on acceptance:**\nsending an invite is free; `add_seat` fires only when the invitee accepts,\nraising the subscription item quantity with\n`proration_behavior=\"always_invoice\"` and an idempotency key on the\ninvitation id so a retried accept cannot double-bill. `remove_seat` lowers\nthe quantity with `create_prorations`, crediting the unused remainder\nagainst the next invoice rather than refunding, with a floor of one seat.\nBoth are no-ops off Business. There is no upper seat bound in the code.\n","what_it_helps_users_do":null}},{"id":"self-serve-plan-management","type":"capability","title":"Self-serve plan management","summary":"Interval and plan changes are not self-serve. The Stripe Customer Portal session endpoint exists but no frontend component calls it, so the interval is chosen at Checkout.","status":"planned","scope":null,"keywords":["portal","interval","checkout","not-shipped"],"body":null}]}