Platform Economics

The economics subsystem enforces rate limits, quotas, and funding lanes per user per request. Cost is reserved before execution and committed on success, released on failure.

Economics Flow

Economics flow diagram
Economics Flow Token budget and rate limit enforcement flow through the platform economics subsystem Request user_type bundle_id Plan Check rate limits concurrency Reservation reserve $2.00 funding lane Execute bundle.run() token counting Commit / Release commit on success release on failure EconomicsLimitException → release reservation

Key Concepts

ConceptDescription
PlanQuota policy identity — defines requests/second, concurrency limits, and token quotas per class of users (anonymous, registered, paid, privileged).
Funding LaneSubscription budget (monthly USD) · wallet credits · project budget. Determines which funding source covers the request.
ReservationCost reserved before execution begins. Committed on completion, automatically released on failure or EconomicsLimitException.

Rate Limit Layers

  1. 1

    Gateway layer

    Requests/second throttling at Ingress. Configurable per tenant via gateway.yaml. Enforces backpressure before tasks are enqueued.

  2. 2

    Economics layer

    Per-user quotas (daily/monthly requests, concurrent sessions, hourly token budgets). Enforced by the economics subsystem at execution time.

💡
Stripe integration is available for subscription and wallet top-up flows. Use BaseEntrypointWithEconomics for automatic enforcement. Always re-raise EconomicsLimitException unchanged.

Bundle Economics & Rate Limiting

from kdcube_ai_app.apps.chat.sdk.solutions.chatbot.entrypoint_with_economic import (
    BaseEntrypointWithEconomics
)

@agentic_workflow(bundle_id=BUNDLE_ID)
class MyBundle(BaseEntrypointWithEconomics):
    @property
    def configuration(self):
        return {"economics": {"reservation_amount_dollars": 2.0}, ...}

Default Quota Policies

User TypeConcurrentReq/DayReq/MonthTokens/Hour
anonymous1260150k
free210030k500k
payasyougo22006k1.5M
admin10unlimitedunlimitedunlimited
⚠️
Always re-raise EconomicsLimitException unchanged. The base report_turn_error() handles this correctly — never catch it silently.

Payment Integration (Stripe)

Stripe handles all external payment flows: wallet top-ups (one-time credits), recurring subscriptions, refunds, and subscription cancellations. Project budgets are never topped up directly from Stripe events — only by admin actions or the subscription rollover job.

Webhook Flow

  1. 1

    Checkout

    User initiates a wallet top-up or subscription via POST /api/economics/stripe/checkout/topup or .../subscription. The API creates a Stripe Checkout Session and returns a redirect URL.

  2. 2

    Stripe fires webhook

    On payment completion Stripe sends an event to POST /api/economics/webhooks/stripe. The handler verifies the HMAC signature, checks idempotency via external_economics_events (keyed by Stripe event ID), and applies the change.

  3. 3

    Reconcile job

    A cron-driven reconcile job (STRIPE_RECONCILE_CRON) catches missed webhooks by fetching Stripe events ordered ascending by created timestamp from a Redis-stored watermark. All replay is idempotent.

Webhook Events Handled

EventAction
payment_intent.succeededTop up wallet (lifetime credits) for wallet_topup kind
invoice.paidTop up subscription period budget; update subscription record
refund.created / refund.updatedFinalize wallet refund pending event
checkout.session.completedWrite stripe_subscription_id to DB (prevents race with invoice.paid)
customer.subscription.updatedSync subscription status and next_charge_at
customer.subscription.deletedMark subscription canceled; rollover unused balance to project budget

Subscription Plans & Funding Lanes

Each subscription plan in the subscription_plans table maps to a Stripe product via stripe_price_id. When invoice.paid fires, the handler tops up the user's subscription period budget (the funding lane for that billing cycle). On period end the rollover job moves unused balance into the project budget funding lane.

Wallet top-ups credit the lifetime credits funding lane directly. Refunds debit lifetime credits and issue a Stripe refund against the original payment_intent_id.

Key Configuration

SettingSourcePurpose
services.stripe.secret_keysecrets.yamlStripe API key (sk_live_ or sk_test_)
services.stripe.webhook_secretsecrets.yamlWebhook signing secret (whsec_)
STRIPE_RECONCILE_ENABLED.envEnable the reconcile cron job
STRIPE_RECONCILE_CRON.envCron schedule (default 45 * * * *)
bypass_throttling_patternsGATEWAY_CONFIG_JSONExclude ^.*/webhooks/stripe$ from rate limiting
⚠️
The webhook endpoint must be excluded from gateway rate limiting via bypass_throttling_patterns. Without this, high-volume webhook bursts during reconcile catch-up may be throttled and Stripe will retry, causing duplicate processing attempts.

Usage Reporting & Aggregations

The OPEX subsystem provides pre-computed accounting aggregates on top of raw usage events. These aggregates power the OPEX API endpoints and avoid rescanning event logs on every request.

Aggregate Levels

LevelStorage PathBreakdown
Hourlyanalytics/<tenant>/<project>/accounting/hourly/YYYY/MM/DD/HH/total.jsonService, provider, model
Dailyanalytics/.../daily/YYYY/MM/DD/total.jsonService, provider, model + per-user (users.json) + per-agent (agents.json)
Monthlyanalytics/.../monthly/YYYY/MM/total.jsonService, provider, model; includes days_covered / days_missing
Yearlyanalytics/.../yearly/YYYY/total.jsonService, provider, model; includes months_covered / months_missing

Usage Event Types

Raw events are written under accounting/<tenant>/<project>/<YYYY.MM.DD>/<service_type>/. Each event carries a service breakdown with service (llm, embedding, ...), provider (anthropic, openai, ...), and model identifiers, plus token counts and a cost basis.

OPEX API Endpoints

EndpointBacked ByDescription
GET /accounting/opex/totalDaily aggregates + raw gap-fillGlobal usage totals with cost estimate for a date range
GET /accounting/opex/usersDaily users.jsonPer-user usage and cost breakdown
GET /accounting/opex/agentsDaily agents.jsonPer-agent usage and cost breakdown
GET /accounting/opex/conversationRaw events (prefix-optimized)Per-conversation usage
GET /accounting/opex/turn/*Raw events (prefix-optimized)Per-turn and per-turn-per-agent usage

Cost Breakdown Example

// GET /accounting/opex/total?tenant=home&project=demo&date_from=2025-11-01&date_to=2025-11-21
{
  "event_count": 1234,
  "cost_estimate": {
    "total_cost_usd": 123.45,
    "breakdown": [
      { "service": "llm", "provider": "anthropic", "model": "claude-sonnet-...", "cost_usd": 78.90 },
      { "service": "embedding", "provider": "openai", "model": "text-embedding-3-small", "cost_usd": 44.55 }
    ]
  }
}

Aggregation Scheduling

A nightly scheduler (driven by OPEX_AGG_CRON, default 0 3 * * * in Europe/Berlin) computes daily and monthly aggregates for yesterday. Cross-instance deduplication uses a Redis lock (acct:agg:{tenant}:{project}:{date}, TTL 4 hours).

Manual Backfill

# Backfill a date range
curl -X POST \
  "http://localhost:8010/accounting/opex/admin/run-aggregation-range?start_date=2025-01-01&end_date=2025-01-10"
💡
The OPEX layer provides metering and pricing only. Budget caps, throttling on budget exhaustion, and remaining-balance tracking are implemented by the calling application on top of the cost estimates returned by these endpoints.