The Content Creation Engine: Multi-Tenant Generation on Real Billing Rails
Content Generator is the estate's content-creation engine, and it answers a product question most AI wrappers skip: not 'can we call an LLM?' but 'can we sell the call?'. It is a multi-tenant platform where the billing spine is the architecture: signup creates a tenant, a user, and a free-plan wallet with 50 included units, and mints an API key exactly once — stored only as a SHA-256 hash, never in plaintext. Every generation request authenticates by key, resolves to a tenant_id, and meters real units against the wallet inside a transaction, with an append-only usage_ledger as the source of truth. Billing is hybrid: when a tenant exceeds the included allowance, requests are billed as overage (2 cents per unit) rather than blocked — and overage is reported to the in-house payment rail (ark-pay, on live Stripe) as meter events made idempotent per job, so a retry can never double-charge. All of this was verified live: a real signup returned a tenant and key, a real generate call produced marketing copy through the LLM gateway, and the usage endpoint reported 50 included, 1 used, 49 remaining. The capability surface is deliberately honest — marketing copy and per-platform social variants are live today; graphics, document, and video generation are labeled 'coming soon' on the landing page because they are on the roadmap, not in the API.
Key Metrics
Sellability
Before
Typical AI-wrapper prototype: unauthenticated, unmetered, nothing to invoice
After
Full billing spine live: hashed-key auth, per-tenant wallet, append-only ledger, Stripe-metered overage — verified signup-to-usage flow in production
Allowance behavior
Before
Hard cutoff at the quota, failing customers mid-campaign
After
Hybrid billing — overage delivered and billed at 2¢/unit, owed cents always visible on /v1/usage
Billing integrity
Before
Direct per-request charges that can double-bill on retry
After
Idempotent Stripe meter events (deduped per job_id) backed by a local ledger that survives payment-rail outages
Tenant isolation
Before
Asserted, untested multi-tenancy
After
Tested invariant: integration suite proves tenant B reads 0 used after tenant A generates; tenant_id scopes every query
Watch the Walkthrough
The Challenge
Turning an LLM call into a sellable product is mostly not an AI problem — it is a billing and tenancy problem. A public generation API needs real tenant isolation (one customer must never see another's usage or data), keys that are safe at rest, and metering that is accurate under failure: a crashed request must not charge, a retried report must not double-charge, and a customer who runs past their allowance should be billed transparently rather than hit a wall mid-campaign. Most prototypes skip all of this — unauthenticated endpoints, plaintext keys, no ledger — and then cannot be monetized without a rewrite. The requirement here was the opposite: build the billing spine first (signup, hashed keys, per-tenant wallet, append-only ledger, Stripe-metered overage), attach the generation capabilities to it, and be honest on the tin about which capabilities are live versus on the roadmap.
Why This Approach?
Billing model
Hybrid wallet — included units per period, overage billed (not blocked) at 2¢/unit
A hard cutoff breaks a customer mid-campaign; pure pay-as-you-go removes the predictable free tier that lets people evaluate. The hybrid wallet gives every tenant 50 included units and then bills overage transparently — the usage endpoint reports included, used, remaining, and estimated owed cents at all times, so there is never a surprise.
Alternatives considered: Hard cutoff at the allowance, pure pay-as-you-go, unmetered flat plans
Overage settlement
Append-only usage_ledger as source of truth, reported to ark-pay as idempotent Stripe meter events
The ledger records every metered unit and its cost locally, so billing survives any outage of the payment rail. Meter events carry the job_id as their idempotency identifier — Stripe dedupes them — so a retried report can never double-charge. Tenants without a payment method simply accrue in the ledger, and /v1/usage reports the owed cents honestly.
Alternatives considered: Charge cards directly per request, trust Stripe as the only record, bill from in-memory counters
Tenancy and key security
SHA-256-hashed API keys resolving to a tenant_id that scopes every query
The hashed key lookup is the single source of tenant identity: every downstream query filters by the resolved tenant_id, and the key itself is returned exactly once at signup and stored only as a hash (the same secret-hashing pattern as the in-house payment rail). An integration test suite proves the boundary — after tenant A generates, tenant B's wallet still reads zero.
Alternatives considered: Plaintext key storage, JWT sessions, a shared demo tenant
Metering-vs-generation ordering
Generate first, meter after — never hold a DB lock across an LLM round-trip
LLM calls take seconds; holding a wallet row lock that long would serialize every tenant's traffic. Generating before the metering transaction keeps locks short — and means a mid-request LLM failure never charges for undelivered work, which matters most on multi-platform social requests where all variants generate before a single unit is metered.
Alternatives considered: Meter optimistically then generate, hold the wallet row lock through generation
Build Process
Billing spine: signup, wallet, ledger
POST /v1/signup creates a tenant, a user, and a free-plan wallet with 50 included units, and mints an API key returned exactly once (SHA-256 hashed at rest, plaintext never stored). Every metered unit lands in an append-only usage_ledger with its capability, units, and cost in cents — verified live with a real signup returning {tenant_id, api_key}.
Metered copy generation
POST /v1/generate/copy takes a prompt and an optional target platform, builds a per-platform system prompt, and generates through the self-hosted LLM gateway using a dynamic model tier (no hardcoded model versions). Verified live: a launch-tweet request returned real marketing copy with a job_id, metered exactly 1 unit — wallet moved from 50/0 to 1 used, 49 remaining.
Per-platform social variants
POST /v1/generate/social turns one brief into per-platform post variants — platforms are normalized and deduped, capped at 5 per request to bound LLM spend, and metered 1 unit each. All variants generate before metering, so a mid-request failure never charges; a single request can straddle the allowance, part included and part billed as overage.
Hybrid overage on real Stripe rails
Units beyond the allowance are billed, not blocked: 2¢ per overage unit accrues in the ledger and is reported to the in-house ark-pay service (live Stripe) as meter events, idempotent per job_id so Stripe dedupes retries. Tenants without an attached payment method accrue owed cents that /v1/usage reports transparently. GET /v1/usage, /health, and a machine-readable /api index round out the live surface.
Challenges & Solutions
Impact
Unauthenticated endpoints and unmetered calls mean there is nothing to invoice — monetizing later requires retrofitting tenancy, keys, and metering under live traffic.
Solution
Build the billing spine first: signup mints hashed keys, every request resolves to a tenant wallet, every unit lands in an append-only ledger, and overage flows to Stripe as metered events.
Result
The live flow is sellable end to end today — verified signup, metered generation, and a wallet reporting included/used/remaining/owed in real time.
How AI Powers This
AI Capability
Prompt-to-Copy Generation
Turn a one-line brief into ready-to-use marketing copy — tuned to the platform you name — through a single authenticated API call
Business outcome
Verified live: a trail-running-shoe launch prompt returned real multi-option tweet copy, metered exactly 1 unit against the wallet
Under the hood
POST /v1/generate/copy {prompt, platform} -> per-platform system prompt -> self-hosted LLM gateway (ark-proxy, dynamic anthropic-medium tier) -> {job_id, content, units_used, remaining_units}
How success is measured: Copy relevance to the brief, platform-convention fit, metering accuracy per call
AI Capability
One Brief, Many Platforms
Feed one campaign brief and get native variants for up to five platforms at once — each written to that platform's tone and format
Business outcome
One request fans out to per-platform variants with bounded LLM spend — and a failed generation mid-request charges zero units
Under the hood
POST /v1/generate/social {prompt, platforms[]} -> normalize+dedupe platforms (cap 5) -> per-platform system prompts -> all variants generated before metering, 1 unit each
How success is measured: Per-platform voice fidelity, dedupe correctness, no-charge-on-failure behavior
AI Capability
Metered AI on Real Payment Rails
Every generated unit is accounted for: customers see included, used, remaining, and owed cents live — and overage settles through real Stripe metering
Business outcome
Verified live wallet math (50 included -> 1 used -> 49 remaining, 0 owed) on a real production tenant
Under the hood
meter_units() transaction -> usage_ledger (source of truth) -> ark-pay (:3890, live Stripe) meter events with job_id as the idempotency identifier; GET /v1/usage reports the wallet
How success is measured: Ledger-wallet consistency, idempotent settlement under retries, honest owed-cents reporting
Results & Metrics
Sellability
ImprovedBefore
Typical AI-wrapper prototype: unauthenticated, unmetered, nothing to invoice
After
Full billing spine live: hashed-key auth, per-tenant wallet, append-only ledger, Stripe-metered overage — verified signup-to-usage flow in production
Allowance behavior
ImprovedBefore
Hard cutoff at the quota, failing customers mid-campaign
After
Hybrid billing — overage delivered and billed at 2¢/unit, owed cents always visible on /v1/usage
Billing integrity
ImprovedBefore
Direct per-request charges that can double-bill on retry
After
Idempotent Stripe meter events (deduped per job_id) backed by a local ledger that survives payment-rail outages
Tenant isolation
ImprovedBefore
Asserted, untested multi-tenancy
After
Tested invariant: integration suite proves tenant B reads 0 used after tenant A generates; tenant_id scopes every query
Capability honesty
ImprovedBefore
Roadmap features marketed as live
After
Landing page labels copy + social as live and graphics/docs/video as 'coming soon' — on the roadmap, not in the API
System Overview
The architecture below is the technical foundation behind every business outcome on this page — built for reliability, low running cost, and the speed your customers feel.
A Rust/Axum multi-tenant service (content-saas, :3960 systemd) in front of PostgreSQL, live at contentgenerator.chakrakali.com. POST /v1/signup creates tenant + user + free-plan wallet (50 included units) and mints an API key returned exactly once — stored only as a SHA-256 hash, and the hash lookup is the sole source of tenant identity for every downstream query (row-level tenant_id on every table, proven by an isolation test suite). Generation endpoints (/v1/generate/copy, /v1/generate/social) call the self-hosted LLM gateway (ark-proxy :3200) with a dynamic model tier, generating BEFORE the metering transaction so no row lock spans an LLM round-trip and failures never charge. Metering writes an append-only usage_ledger (the billing source of truth); units beyond the allowance are billed as overage (2¢/unit default) and reported to ark-pay (:3890, live Stripe) as meter events idempotent per job_id. GET /v1/usage reports the wallet (included/used/remaining/owed cents), with /health and a machine-readable /api index alongside. Deliberately separate from the internal cockpit content-studio — own repo, service, database, and auth. API-first: there is no web dashboard yet, and unreleased capabilities (graphics, documents, video) are labeled 'coming soon' rather than claimed.Technologies Used
Rust, Axum, PostgreSQL, SHA-256 key hashing, usage ledger + wallet metering, Stripe meter events via ark-pay, ark-proxy LLM gateway, systemd binary deploy