Skip to main content

Overview

The platform credit billing system converts all external provider costs into a common credit system, applies configurable margin at the cost-event level, deducts credits where external costs are incurred, and provides superadmin-only cost-vs-sale visibility.

Pricing Model

Default configuration stored in platform_billing_config: For each external cost event:
Example: If raw cost is 0.01,chargedcostis0.01, charged cost is 0.02. Credits burned = 0.02/0.02 / 0.50 = 0.04 credits.

Database Schema

Core Tables

Analytics View

Atomic Debit Function

record_external_cost_event(...) performs all billing writes in one transaction:
1

Load Defaults

Load credit_value_usd and margin_multiplier from billing config.
2

Ensure Account

Ensure organization billing account exists (create if not).
3

Lock Wallet

Lock wallet row with FOR UPDATE for concurrency safety.
4

Calculate

Calculate charged_usd and credits_burned.
5

Update Wallet

Update wallet balances and counters.
6

Record Cost Event

Insert into external_cost_events.
7

Record Ledger Entry

Insert matching row in organization_credit_ledger.
8

Return Result

Return billing result payload (event id, burn, charged, balance after).
This function is the canonical low-level billing entry point. All provider cost recording must go through this function.

Current Coverage Matrix

Mandatory Integration Contract

Any new integration that incurs provider cost MUST integrate with credit billing from the first implementation.

Requirements

  1. Identify cost-incurring operations at the provider boundary
  2. Record costs using record_external_cost_event(...) in the same execution path
  3. Pass organizationId (required) and userId (when available) to the billing call
  4. Store normalized metadata: provider, operation, reference_type, reference_id
  5. Define failure policy:
    • Strict: fail request if billing write fails
    • Best-effort: log and continue (only for non-critical async paths)
  6. Add tests verifying:
    • External cost event row is created
    • Ledger row is created
    • Expected margin/credit conversion is applied

New Knowledge Base Connector Checklist

  1. Connector jobs include organizationId and userId in job payload
  2. Embedding generation routed through EmbeddingService (billing is automatic)
  3. If connector calls paid third-party APIs, add a billing event for that API call
  4. Set connector-specific reference_type values (e.g., kb_connector_sync)
  5. Add integration tests for indexing success and retry/idempotency

New Publish Destination Checklist

  1. Treat outbound provider calls as billable operations
  2. Add billing calls at the destination adapter layer (not only in route handlers)
  3. Use operation names mapping to destination actions (publish_send, publish_webhook)
  4. Include destination/channel IDs in metadata for auditing
  5. Add dashboard-facing provider normalization for readable superadmin reporting

Superadmin Reporting

Frontend: apps/web/src/components/billing/PlatformBillingDashboard.tsx — visible only when user.isSuperAdmin === true. Response includes: totals, daily trend, provider rollup, organization rollup, and plan mix.

Service Integrations

  • bot.service.ts: Chat cost calculated from synced model pricing, calls BillingRepository.recordExternalCost(...) after each completion
  • billing.repository.ts: Wraps record_external_cost_event, exposes getPlatformSummary() for dashboard

Access Control

Superadmin emails configured via:
  • Backend: PLATFORM_SUPERADMIN_EMAILS
  • Frontend: NEXT_PUBLIC_PLATFORM_SUPERADMIN_EMAILS
Bot service route rejects non-superadmin callers with 403.

Operational Notes

  • Migration 014_platform_credit_billing.sql is idempotent (safe to re-run)
  • Keep gateway proxy from forwarding content-length when body is reserialized
  • Billing function uses row locking for consistent wallet debits under concurrency

Future Extensions

  • Stripe checkout + invoice sync into organization_credit_ledger
  • Auto top-up workers based on wallet thresholds
  • Plan upgrade/downgrade lifecycle automation
  • Hard balance floor and configurable overage behavior per plan