This guide shows how to enforce an LLM token allowance on AI Gateway traffic. Metering LLM traffic tells you what a customer consumed, but it doesn’t stop them consuming more. The Entitlement Enforcement plugin closes that gap: it polls the Metering & Billing Entitlement Access API for the customer’s remaining token allowance and blocks requests once the allowance is spent.
In this guide, you’ll:
- Create a Kong Gateway Consumer that you’ll map to a customer
- Route LLM traffic through the AI Gateway AI Proxy plugin
- Set up a meter for LLM tokens and a feature that counts only prompt tokens
- Create a plan that grants a token allowance as a metered entitlement, and publish it
- Create a customer and start a subscription so the entitlement is active
- Enable the Metering & Billing plugin to report token usage, and the Entitlement Enforcement plugin to enforce the allowance
- Verify that LLM requests are allowed until the token allowance runs out, then blocked
Enforcement needs configuration on both sides, and the pieces reference each other. The following table lists what you’ll create, why each piece is needed, and what it connects to:
|
What you configure |
Where |
Why it’s needed |
|---|---|---|
example-service and example-route
|
Prerequisite | The entities the plugins attach to. The Entitlement Enforcement plugin is enabled on the Route, so it runs for traffic matching that Route only. |
| Two Konnect system account tokens | Prerequisite | One with the Ingest role for reporting usage, one with the Entitlement Access role for reading entitlements. The roles are separate, so a single token can’t do both unless it has the Admin role. |
| OpenAI API key | Prerequisite | AI Proxy authenticates to OpenAI with it. Without a working model call there are no tokens to meter or enforce. |
| Redis | Prerequisite | Where the plugin caches enforcement state: a background timer writes the state it fetches from Metering & Billing, and each worker syncs its local cache from Redis. The plugin can’t enforce without a reachable Redis. |
Consumer with a pinned id
|
Kong Gateway |
Identifies the client. The pinned id fixes the consumer:<id> subject key that both plugins use, so the customer you create later can be matched to it.
|
| Key Auth plugin | Globally | Authenticates the request so Kong Gateway can resolve a Consumer. Without an authenticated Consumer, there’s no customer to enforce against. |
| AI Proxy plugin, with statistics enabled |
example-service
|
Proxies chat requests to the model and reports the token counts. Token metering depends on log_statistics.
|
| Meter that sums tokens | Metering & Billing | Counts the tokens reported for each LLM request. This is the usage the allowance is measured against. |
| Metered feature, filtered to prompt tokens | Metering & Billing |
Makes token usage enforceable, and restricts what counts to OpenAI prompt tokens. Its key is what you set as the plugin’s feature.key.
|
| Plan with a token entitlement, published | Metering & Billing | Defines the allowance in tokens, on a rate card that references the feature. |
| Customer with a matching subject key | Metering & Billing |
The entity whose access is enforced. Its usage_attribution.subject_keys must contain the Consumer’s subject key, or usage and enforcement won’t resolve to this customer.
|
| Subscription to the plan | Metering & Billing | Materializes the entitlement onto the customer. Until the subscription starts, the customer has no entitlement to enforce. |
| Metering & Billing plugin, with the Ingest token |
example-service
|
Reports token usage events. Nothing counts against the allowance unless usage is reported, and allow_status_codes keeps failed responses out of that usage.
|
| Entitlement Enforcement plugin, with the Entitlement Access token |
example-route
|
Reads the customer’s remaining token allowance and blocks the request once it’s spent. |
The following diagram shows how those pieces relate:
flowchart TB
client(["Client (API key)"])
subgraph gateway["Kong Gateway"]
route["example-route"]
service["example-service"]
consumer1["Consumer (Kong Air)"]
enforcement["Entitlement Enforcement plugin"]
proxy["AI Proxy plugin"]
metering["Metering & Billing plugin"]
end
redis[("Redis
enforcement cache")]
openai(["OpenAI (gpt-4o)"])
subgraph mb["Konnect Metering & Billing"]
events["Events API"]
access["Entitlement Access API"]
meter["Meter (LLM tokens)"]
subgraph plan["Token Plan"]
feature2["Metered feature + entitlement (token limit)"]
end
subgraph subscription["Token Subscription"]
customer1["Customer (Kong Air)"]
end
end
client -->|chat request| route
route -.->|enforced by| enforcement
route -->|allowed| service
service -.->|proxied by| proxy
proxy -->|prompt| openai
service -.->|metered by| metering
client -.->|authenticates as| consumer1
consumer1 -->|subject key| customer1
metering -->|token usage events, Ingest token| events
events -->|aggregated by| meter
meter -->|referenced by| feature2
subscription -->|activates| plan
enforcement -->|queries, Entitlement Access token| access
access -->|reads entitlement| customer1
enforcement <-->|cached state| redis
feature2 -.->|feature.key| enforcement