Skip to content

Billing and usage ​

OpenBrain bills organizations (not individual users) via Laravel Cashier and Stripe.

Plans ​

  • Configure Stripe Price IDs in .env (STRIPE_PRICE_HOBBY, STRIPE_PRICE_PRO).
  • Plan copy and marketing labels live in config/openbrain.php under plans.
  • Checkoutable plan keys are hobby and pro.

Subscribing ​

  1. Sign in to the dashboard at /app.
  2. Open Billing for your organization.
  3. Owners can start Subscribe on Hobby or Pro (POST Checkout with required plan=hobby|pro) when the organization has no subscription, or the previous one has ended. An existing Stripe customer can check out again. Pro Checkout includes a 14-day trial; Hobby is billed immediately.
  4. While a subscription is active, trialing, in its grace period, past_due, incomplete, or unpaid, use Manage subscription (Customer Portal) for the payment method, invoices, cancellation, and plan changes. Confirm payment appears when Cashier reports an incomplete payment. Checkout is not offered again until the subscription has ended.
  5. In the Customer Portal, enable both Hobby and Pro products so customers can switch plans.
  6. After Checkout, the success URL returns to Billing with checkout=success. The subscription row appears when Cashier processes customer.subscription.created. Until then the page shows a pending notice and writes stay unavailable. Cancel returns with checkout=cancelled and Subscribe stays available.

What the Billing page shows ​

FieldSource
Subscription status / plan / trial / grace periodLocal Cashier tables (subscriptions), kept in sync by Stripe webhooks — not a live Stripe API read on page load
Stripe customer IDLocal organizations.stripe_id (set when Checkout creates the customer)
Ingest / search usageLocal organization_usage meters (app quotas), not Stripe metered billing
Plan and monthly capsResolved from the synced subscription price (see Plan limits)

After Checkout returns, status may briefly show none until customer.subscription.* webhooks are processed.

Reads stay free, writes need a plan ​

When OPENBRAIN_BILLING_ENFORCED=true:

Operation groupOperationsUnpaid organization
Writesingest, upsert, batch, update, delete402 Payment Required (code: "entitlement_required"; MCP returns a tool error)
Readssearch, get, recent, export, stats, changes, MCP read tools and resourcesAllowed

The same rule applies on every surface: REST, MCP, the dashboard (including Filament delete actions), and inbound GitHub/Linear webhooks. Inbound webhook deliveries that are denied are dropped without retry — no memory and no usage is recorded.

If OPENBRAIN_BILLING_ENFORCED=true while STRIPE_SECRET is empty, entitlement cannot be verified. Writes then fail closed with 503 Service Unavailable (code: "service_unavailable") instead of being silently allowed; reads continue to work.

Local development typically leaves enforcement off and omits STRIPE_SECRET.

Usage metering ​

Per-organization counters are stored monthly (organization_usage):

  • ingest_count — ingest, upsert, and accepted batch items
  • search_count — search, export, stats, changes, and recent

get, list, and dashboard record views are not metered. Dashboard semantic search and JSONL export follow the same metering and policy rules as their API equivalents.

Exceeding a cap returns 429 with code: "quota_exceeded" (MCP: tool error) until the next monthly period.

Plan limits ​

While OPENBRAIN_BILLING_ENFORCED=true, caps come from the organization's plan:

PlanMonthly ingestMonthly search
Free (no subscription)0 (writes require a plan)1,000
Hobby10,00050,000
Pro100,000500,000
Trialmirrors Promirrors Pro

Override the defaults with:

env
OPENBRAIN_FREE_SEARCH_LIMIT=1000
OPENBRAIN_HOBBY_INGEST_LIMIT=10000
OPENBRAIN_HOBBY_SEARCH_LIMIT=50000
OPENBRAIN_PRO_INGEST_LIMIT=100000
OPENBRAIN_PRO_SEARCH_LIMIT=500000

In each plan's limits under openbrain.plans, 0 allows nothing and -1 means unmetered.

An active subscription on a price that matches neither STRIPE_PRICE_HOBBY nor STRIPE_PRICE_PRO gets no plan allowance at all: it never inherits a paid cap and never becomes unmetered. OpenBrain logs a warning and every metered operation (ingest, upsert, batch, search, export, stats, changes, recent) returns 503 with code: "service_unavailable" until the price is mapped, and the Billing page shows the mismatch. Fix it by pointing STRIPE_PRICE_HOBBY / STRIPE_PRICE_PRO at the price IDs your customers are actually subscribed to.

Legacy global limits (enforcement off) ​

While OPENBRAIN_BILLING_ENFORCED=false, plan limits are ignored and the legacy global caps stay authoritative, where 0 means "no cap":

env
OPENBRAIN_USAGE_LIMIT_INGEST=0
OPENBRAIN_USAGE_LIMIT_SEARCH=0

Webhooks ​

Cashier registers POST /stripe/webhook. Set STRIPE_WEBHOOK_SECRET and forward events from Stripe (or stripe listen locally).

Environment ​

VariablePurpose
STRIPE_KEYPublishable key
STRIPE_SECRETSecret API key
STRIPE_WEBHOOK_SECRETWebhook signing secret
STRIPE_PRICE_HOBBYHobby plan price ID
STRIPE_PRICE_PROPro plan price ID
OPENBRAIN_BILLING_ENFORCEDRequire an active subscription for memory writes
OPENBRAIN_FREE_SEARCH_LIMITMonthly search cap for unpaid organizations
OPENBRAIN_HOBBY_INGEST_LIMITMonthly ingest cap on Hobby
OPENBRAIN_HOBBY_SEARCH_LIMITMonthly search cap on Hobby
OPENBRAIN_PRO_INGEST_LIMITMonthly ingest cap on Pro (and trials)
OPENBRAIN_PRO_SEARCH_LIMITMonthly search cap on Pro (and trials)
OPENBRAIN_USAGE_LIMIT_INGESTLegacy ingest cap, used only while enforcement is off (0 = off)
OPENBRAIN_USAGE_LIMIT_SEARCHLegacy search cap, used only while enforcement is off (0 = off)