Skip to main content

Subscription & Billing System

How Ever Works charges for itself, end to end. The behaviour spec is docs/specs/features/billing/spec.md; the implementation lives in packages/agent/src/subscriptions/ and apps/api/src/billing/. Everything sells through the shared "Ever Tech" Stripe account under the ever_works_* lookup-key convention (packages/agent/src/subscriptions/billing/stripe-catalog.data.json, applied by scripts/stripe-sync-catalog.mjs — see the billing operations runbook).

The three things Ever Works sells​

WhatShapeWhere priced
PlansFree / Pro $25 / Enterprise $199 per month on cloud (annual $204 / $1,668); self-hosted Pro $49/mo, $408/yr or a $99 one-time perpetual licence; Enterprise Edition $199/mocatalog + subscription_plans seed
Seats10 included on paid tiers; +$5 (Pro) / +$10 (Enterprise) per additional seat per month. A seat is an employee OR an agentcatalog seat prices
Credits1 credit = 1¢ of platform-billed AI usage. Daily allowance 50 on every plan; monthly allowance 3,000 (Pro) / 25,000 (Enterprise) expiring at each allowance-month end; prepaid packs $10/1,000 · $50/5,500 · $200/25,000 (never expire); pay-as-you-go beyond the balance, opt-in, metered and billed in arrearscredit-packs.ts + the catalog payg section

Plan codes are identities (free / standard / premium) and never change; standard is displayed as "Pro" and premium as "Enterprise".

Credits pipeline​

  1. Metering — every AI call lands in plugin_usage_events with costCents at provider list price (AiFacade.calculateCost).
  2. Settlement — when a run reaches a terminal state, RunCostSettlementService sums the run's billable spend (BYOK-exempt plugins removed), stamps agent_runs.costCents, and converts the billable part to credits: ceil(costCents × (CREDITS_PER_DOLLAR/100) × (1 + margin)). The margin defaults to the catalog's creditsMarginPercent (35). That is the default CREDITS_SETTLEMENT_MODE=provider_cost. With price_list, calls priced by a fixed per-unit entry on the published credit price list (web search, page extraction, screenshot) debit their listed credits instead, and everything else still converts from cost. Usage rows carry the list price in both modes; GET /api/credits/pricing reports the active mode as settlementMode.
  3. Ledger — one consumption row per run (run:{runId}), allocated against credit buckets soonest-expiring first. Balance = available sum of the ledger; see Credits & Billing.
  4. Overflow — if the balance cannot cover the debit and pay-as-you-go is on, the remainder (up to the monthly cap headroom) becomes a credit_meter_events row and a Stripe meter event; Stripe rates it under the graduated metered price and invoices in arrears.
  5. Enforcement — the dispatch gate parks new runs for credit-limited plans with no balance and no pay-as-you-go headroom (CREDITS_ENFORCEMENT defaults on iff Stripe is configured).

Seats​

A seat is an employee OR an agent — interchangeable, which is the point of the product. Paid plans include 10; extras are billed per seat per month from the catalog ($5 Pro / $10 Enterprise).

  • Counted tenant-wide. Access in Ever Works is tenant-wide, so somebody who belongs to three Organizations in one Tenant occupies ONE seat, and an agent built by a team member is capacity exactly like one the owner built. Archiving an agent frees its seat.
  • Persisted from the provider. user_subscriptions.seats / providerSeatItemId are reconciled from the subscription's items on every subscription.* delivery (the seat item is the one whose price lookup_key carries the _seat_ infix), never guessed locally. NULL means "fall back to the plan's seatsIncluded" — never zero, which would read as "no seats allowed".
  • Enforced before the write. Inviting a member (at invite AND at accept) and creating an agent ask SeatsService.assertSeatAvailable for the Tenant owner first; a full allowance surfaces as 402 with the counts. The check fails OPEN on everything else: subscriptions disabled, an unbounded plan, or any resolution error never blocks adding a teammate.
  • Adjustable. POST /api/billing/seats takes the TOTAL wanted (a total, not a delta — a delta double-charges on a retry); the server bills max(0, total − included) from the stored plan row and refuses to drop the allowance below what is already in use.

Stripe integration (the provider seam)​

BillingProvider is the vendor-neutral seam; StripeBillingProvider is the only file that imports the Stripe SDK. It uses:

  • Checkout Sessions — mode: payment for credit packs and the perpetual licence, mode: subscription for plans (+ seat line items), mode: setup for card capture. Every session that CHARGES carries Stripe Tax (automatic_tax + customer_update + tax_id_collection); mode: setup deliberately does not, because saving a card charges nothing. The pay-as-you-go subscription carries automatic_tax too.
  • PaymentIntents (off-session) — threshold auto-recharge.
  • Subscriptions — plans, and one usage-only subscription per owner for pay-as-you-go (billing_thresholds.amount_gte = $50 for mid-cycle invoicing; cancelled immediately with invoice_now on disable).
  • Billing Meters — ever_works_credits, aggregation sum by stripe_customer_id; meter events are keyed run:{runId} (identifier = request idempotency key), retried by the credits-meter-flush cron and given up after 23 hours for manual reconciliation. This stays inside Stripe's 24-hour idempotency window and prevents a late retry from double-counting usage after the request key expires.
  • Webhooks — signature-verified, normalized to a closed event union; every ledger write is idempotent on the provider event id. The pay-as-you-go subscription's lifecycle normalizes to payg.updated and can never move a plan tier; its invoices are tagged subscriptionKind: 'payg' so a payment failure suspends overflow and a payment resumes it.
  • Customer Portal — the past-due recovery surface.

Scheduled jobs​

TaskCadenceDoes
credits-daily-grant00:05 UTCexpire lapsed buckets → daily allowance top-ups → monthly plan-allowance grants
credits-meter-flushevery 5 minresend meter events the settlement path could not deliver

Legacy: per-run pay-per-use (deprecated)​

The 2026-05 design (WorkScheduleService billingMode=usage, UsageLedgerService.recordUsage, PAY_PER_USE_PRICE_USD, BillingProvider.recordUsageCharge) predates credits. recordUsageCharge is a no-op on every provider and overagePricePerRun is never billed — the path only writes usage_ledger_entries rows in pending. It is superseded by credits + pay-as-you-go, kept only until its removal is confirmed, and must not be extended.

Configuration​

EnvMeaning
SUBSCRIPTIONS_ENABLEDmaster switch for plan resolution/gating (default off)
STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRETthe money path; both blank = manual provider, everything fails closed
PAYMENTS_ENABLED (web)shows the live purchase surfaces instead of coming-soon
CREDITS_ENFORCEMENTon/off; unset = on iff Stripe is configured
CREDITS_PER_DOLLAR / CREDITS_MARGIN_PERCENT / CREDITS_DAILY_FREEconversion knobs; margin defaults to the catalog (35)
CREDITS_SETTLEMENT_MODEprovider_cost (default) or price_list; see Credits pipeline
PAYG_MAX_MONTHLY_CAP_CREDITSceiling for a self-service pay-as-you-go cap