.jpg)
Consumption Pricing: How It Works + Implementation Guide
Learn how consumption pricing works, the infrastructure it requires, and how engineering teams implement usage-based pricing.
Multi-tenant architecture explained with core components and best practices. Learn how to handle concurrency, enforcement, and usage limits at scale.
.png)
Two agent sessions hit the same tenant credit balance at the same time, both read the same available credits, and both go through because the enforcement check ran after the request instead of before it.
That is the failure mode multi-tenant architecture introduces the moment usage becomes concurrent, and it is the one that is hardest to catch in testing because it only shows up under real load.
Multi-tenant architecture is built from a set of core components that work together to handle tenant context, data isolation, access control, usage tracking, enforcement, and billing. Each layer plays a role in keeping shared infrastructure consistent and reliable under load.
Every request in a multi-tenant system must carry a tenant ID. Without it, the system has no way to evaluate access rules, usage limits, or credit state.
Tenant context is resolved early in the request lifecycle, at the API gateway or middleware layer, and propagated through the stack via headers, JWT claims, or request-scoped context objects.
The failure mode is partial propagation. When a service handles a request without tenant context, it either falls back to a default (wrong) or throws an error. Both outcomes are production problems.
Data isolation defines how tenant data is separated inside shared infrastructure.
Three models cover most architectures:
The choice affects cost, compliance posture, and migration strategy.
Most teams start with row-level isolation and encounter its limits when auditors ask for tenant data extracts, or when a single tenant's query volume starts affecting others.
Entitlements define what a customer can access based on their plan, including which features they can use, how much of them, and under what limits.
RBAC operates at a different level, focusing on what roles can do inside the product, while entitlements shape what a tenant is allowed to use in the first place.
An entitlements layer holds:
Enterprise AI customers arrive with org hierarchy requirements that most entitlement systems weren't built for: per-agent caps, per-team credit pools, department spend limits, and workspace overrides all enforcing at the same time.
Once you're resolving that many dimensions on every request, a simple credits table stops being an entitlement system and starts being a liability.
The entitlements layer needs a single place to resolve decisions, because once access logic is spread across services, each one starts operating on its own view of state, and those views inevitably drift over time.
This is where inconsistencies show up, as one service allows a request while another blocks it depending on cache state, load conditions, or deployment timing.
Stigg centralizes entitlements across the full product catalog. Entitlement resolution draws from the active plan, parent plan, add-ons, active trials, and promotional overrides. When multiple sources apply, the most generous value wins, which removes ambiguity from enforcement logic.
Metering is the process of tracking feature usage in real time and attributing it to a tenant, focusing on accurate measurement and control of consumption as it happens.
Most teams start with event tracking: a JSON event is emitted when something happens (a token is consumed, an API call is made, a file is processed), and a counter is incremented.
Credit tracking tells you:
Credit systems require more structure than counters. Credits are issued in blocks with expiry dates and a cost basis. Paid and promotional credits are tracked as separate categories.
Burn order matters, with promotional credits used before paid ones and expiring credits consumed before non-expiring balances. Depletion behavior can be configured so a hard limit stops the request, while a soft limit allows it to continue with an alert or grace period.
Credits are tracked through an append-only ledger where every grant, deduction, expiry, and reversal is written as an immutable event. The current balance is always derivable from the transaction history, never stored as a single field that can drift.
When real money depends on that record being accurate, the difference between a counter and a ledger is the difference between a number and a financial record.
The enforcement layer is where access decisions are applied. It sits in the request path and evaluates three things:
The response carries more than a boolean. It returns access status, the usage limit, current usage, and whether the feature is unlimited, so the application has everything it needs without extra calls.
The evaluation has to happen synchronously. A check that runs after the request completes is reporting, not enforcement, and by the time it fires the overage has already posted.
Stigg's Sidecar runs as a Docker container inside the customer's own cloud, caching entitlement state in local Redis so most checks resolve immediately.
On cache misses, it falls back to Stigg's Edge API at around 100ms with a configurable timeout.
For teams with data residency requirements, the Sidecar deploys inside your own VPC, keeping tenant entitlement state within your infrastructure boundary.
The Sidecar auto-scales without engineering effort. If the Stigg service loses availability, the local cache keeps enforcement running without falling back to open access or blocking all requests.
Billing handles what happens after access decisions, including invoices, tax, compliance, and payment processing, with tools like Stripe, Zuora, and Chargebee operating here.
By the time billing runs, entitlements have already decided what was allowed and metering has recorded usage, so billing works on finalized data rather than making real-time decisions.
This separation matters because billing systems focus on financial accuracy and compliance, while access control needs to run synchronously during each request.
Stigg sits alongside billing and handles:
Billing continues to handle:
Teams like Webflow use this setup to manage pricing, localization, and credits through configuration, which reduces engineering work and keeps billing infrastructure unchanged.
These best practices focus on the parts of multi-tenant architecture that usually fail first. That includes tenant context propagation, shared state, concurrent usage updates, and runtime enforcement across services.
Tenant context should be resolved before application logic runs, then passed through every service call, job, event, and log line.
In practice, this means the tenant ID should be mandatory at the gateway or middleware layer, validated against the authenticated subject, and carried through headers, JWT claims, or request-scoped context.
The failure mode is usually partial propagation. A background job, webhook handler, or internal service receives a request without tenant context, and either falls back to a default tenant or applies a generic rule.
That turns tenancy into an implicit assumption, which is where isolation and enforcement bugs start.
Usage limits need to be checked before the action consumes resources. For AI products, that might mean checking credits before a model call starts, checking API quota before the request fans out, or checking feature access before a long-running workflow begins.
The key is that the enforcement decision needs to happen while the system can still stop the request. Batch reconciliation can still be useful for reporting and finance workflows, but it cannot protect shared infrastructure from overuse during live traffic.
Feature access, usage limits, plan overrides, trials, add-ons, and credit rules need one authoritative place to resolve. When each service carries its own copy of plan logic, every pricing change becomes a coordination problem across code paths, caches, and deployments.
A centralized entitlements layer gives services a narrow contract: ask whether the tenant can perform the action, then act on the response. That response should include more than allow or deny.
It should return the effective limit, current usage, remaining balance, and the reason behind the decision so the product can respond correctly.
Every usage increment or credit decrement should be safe under concurrent requests. The common bug is a read-modify-write flow where two requests read the same balance, both pass, and both decrement afterward.
A stronger design uses one of these patterns:
For credit systems, an append-only ledger is usually a better primitive than a mutable counter because it gives you a traceable record of issuance, consumption, expiration, reversal, and adjustment.
Multi-tenant systems create hot tenants. One large customer, one agent workflow, or one bursty workspace can generate many concurrent requests against the same limits and balances. If the usage system assumes average traffic, it will fail exactly where the business cares most.
Design the concurrency model explicitly by deciding where locks live, which operations need serialization, which updates can tolerate eventual consistency, and how retries should behave when the original request has already succeeded.
This belongs in the infrastructure design phase, because it shapes how reliably usage state holds under load.
When AI agents are running, entitlement check volume stops being predictable. Millions of checks per day across concurrent sessions and org hierarchies is normal, and the enforcement layer has to resolve all of it locally without adding latency the application can't absorb.
Billing systems are built to calculate invoices, handle taxes, manage payments, and support finance workflows. Enforcement systems need to make low-latency decisions during product usage.
Keep the boundary clean:
This keeps platforms like Stripe, Zuora, Chargebee, and others focused on billing, while the runtime layer controls access, usage, and credits inside the product.
Stripe processes the payment after the purchase decision. Stigg enforces what the purchase allows before each request runs. One operates on settled data, the other operates on live state.
Every service that makes access decisions needs the same effective view of tenant state. The hard part is cache invalidation. TTL-based refreshes create windows where plan changes, credit depletion, or limit updates are applied in one part of the system while remaining stale elsewhere.
Use change-driven invalidation where possible. When a plan, entitlement, or credit balance changes, publish an event that updates the enforcement layer and invalidates stale entries.
Services should avoid owning entitlement state directly; they should query the runtime layer or rely on a local cache that is fed by the same source of truth.
Unit tests confirm the rule works, while load tests show whether it holds when many requests hit the same state at once, which is where multi-tenant systems tend to break.
Run tests on the scenarios that usually surface issues in multi-tenant systems:
The goal is to test the enforcement path as well as the billing output. If the system only looks correct after reconciliation, it can still leak usage during production traffic.
Multi-tenant systems tend to break in consistent ways once traffic becomes concurrent and state is shared across services, where small timing gaps and inconsistent views of data start to surface as real user impact.
Here are the common ways multi-tenant systems break once traffic becomes concurrent and state is shared across services:
When two or more requests hit the same tenant balance at the same time, each one can read the same available state before any update is written back.
Both requests proceed, and the system ends up allowing more usage than intended. This pattern is common in read-modify-write flows and becomes harder to control as traffic increases.
In distributed systems, different services often cache tenant plans, limits, or usage data. When a change happens, such as a plan upgrade, those services update at different times.
For a short window, each service enforces a different version of the truth, which leads to conflicting behavior across the product.
Caches refresh on intervals or TTLs, while usage changes continuously. When a tenant reaches a limit, cached state can still show available capacity, which allows requests to continue. At scale, these small windows add up and create predictable over-consumption patterns.
When enforcement logic is embedded inside individual services, coverage becomes uneven. Some services enforce limits correctly, while others miss checks or apply them differently. Requests routed through those gaps bypass enforcement, which creates inconsistencies that are difficult to trace.
Systems that focus on accurate metering and billing capture what was used, but they do not intervene during the request. This means usage is recorded correctly while consumption continues unchecked, which is how overages accumulate even when tracking looks accurate.
These issues become visible when systems move from controlled testing into real traffic, where concurrency, distributed state, and shared infrastructure expose gaps in how decisions are applied across the request path.
Multi-tenant architecture requires real-time enforcement because shared state and concurrent requests can allow over-consumption unless decisions are made during the request itself.
Logical isolation at the data layer keeps tenant data separate, which helps with access control and compliance, but it does not control how resources are consumed in real time. When multiple requests hit the same tenant state at once, usage can exceed limits if enforcement is delayed.
The issue comes down to timing. Enforcement that runs after the request, whether through billing cycles, cache refreshes, or batch processes, is reacting to usage that has already happened. Under concurrent load, that window is long enough for overages to accumulate before anyone sees them.
Three specific patterns cause this:
Real-time enforcement moves that decision into the request path, where each request carries tenant context and the system evaluates current entitlements before allowing the action to complete. Access, limits, and credit balances apply at the moment of use instead of after usage has already been recorded.
At a system level, this separates reporting from control:
In multi-tenant systems, this distinction defines whether shared infrastructure remains predictable under load, since consistent enforcement at the request level is what keeps usage within defined boundaries.
Single-tenant architecture makes sense when data residency requirements are strict, when a single customer's workload justifies a dedicated environment, or when compliance certification requires physical separation.
Multi-tenant architecture is the default for AI products and most modern software businesses because the operational leverage is significant. The engineering cost is complexity in the enforcement and state management layers, complexity that can be addressed with the right architecture.
Most engineering teams already have the outer pieces of multi-tenant architecture in place:
What is missing is a centralized runtime enforcement layer that sits between the request and the action. This layer holds the entitlements state for every tenant, evaluates limit checks synchronously, and returns an access decision before the service proceeds.
Building this layer in-house is a legitimate choice that many engineering teams start with, where a simple credits table and a decrement function are enough to cover early requirements.
The complexity compounds as the system evolves beyond simple credit tracking and starts handling multiple dimensions of usage and allocation.
This is where a simple credits table starts to fall short, as each added dimension introduces state coordination and enforcement complexity across the system.
A good example is Webflow, whose VP of Engineering estimated that a simplified in-house build would have taken around five engineers six months and that building something at the scale of Stigg itself would take five engineers over a year.
Multi-tenant systems succeed or fail on isolation. Every request needs to resolve against the correct tenant state, apply the correct entitlements, and consume from the correct budget pool without introducing latency or cross-tenant leakage.
Stigg provides that runtime layer:
If you're mapping where enforcement fits into a multi-tenant stack, take a look at how Stigg's runtime layer plugs in alongside your existing billing infrastructure.
Multi-tenant architecture is a design where a single application instance serves multiple customers on shared infrastructure, with tenant data and access separated in software. Each request carries tenant context so access, limits, and usage can be evaluated correctly under concurrent load.
The main difference between single-tenant and multi-tenant architecture is that single-tenant runs a separate infrastructure instance per customer, while multi-tenant serves all customers from a shared instance. Single-tenant provides stronger isolation, while multi-tenant improves efficiency and requires software-based enforcement.
Multi-tenant architecture handles data isolation through row-level isolation, schema isolation, or database isolation. Each approach separates tenant data at different layers, with tradeoffs across cost, operational complexity, and compliance requirements.
The biggest challenge in multi-tenant architecture is maintaining correct enforcement under concurrent requests across shared infrastructure. Systems need atomic updates, consistent state, and request-level enforcement to keep usage within defined limits.
Usage limits in a multi-tenant system are enforced in the request path before resources are consumed. The system evaluates entitlements, usage state, and credit balance, then returns a decision that allows or blocks the request in real time.