Skip to main content

Routes and Consumer Groups

Path- and header-based route matches and API key-based consumer groups select policy chains and request-count limits for supported gateway requests.

Routes

The live gateway uses routes: to select a per-route policy chain for Chat Completions (POST /v1/chat/completions) and Responses (POST /v1/responses) requests. Other request families, including Embeddings, do not currently run route resolution. Without a matching route chain, the request uses the global chain.

The schema also accepts route-level upstream and strip_path fields, but the live request handlers do not consume either field. Configure provider selection under providers: and do not rely on routes to change the provider or forwarded path.

Basic path routing

pack:
name: config-routes-and-consumers-routes-1
version: 1.0.0
enabled: true
providers:
targets:
- id: openai-primary
provider: openai
model: gpt-5.4-mini
secret_key_ref:
env: KEEPTRUSTS_OPENAI_API_KEY
policies:
chain:
- audit-logger
- prompt-injection
- pii-detector
policy:
audit-logger: {}
prompt-injection: {}
pii-detector:
action: redact
routes:
- name: chat
path: "/v1/chat/completions"
match: exact
chain:
- prompt-injection
- pii-detector
- name: responses
path: "/v1/responses"
match: exact
chain:
- audit-logger

Full route reference

pack:
name: config-routes-and-consumers-routes-2
version: 1.0.0
enabled: true
providers:
targets:
- id: openai-primary
provider: openai
model: gpt-5.4-mini
secret_key_ref:
env: KEEPTRUSTS_OPENAI_API_KEY
policies:
chain:
- audit-logger
- prompt-injection
- pii-detector
policy:
audit-logger: {}
prompt-injection: {}
pii-detector:
action: redact
routes:
- name: engineering-chat
path: "/v1/chat/completions"
match: exact
methods:
- POST
headers:
X-Team: engineering
priority: 10
chain:
- prompt-injection
- pii-detector

Route fields

FieldTypeRequiredDefaultDescription
namestringyesUnique route identifier used by schema validation and diagnostics
pathstringyesURL path pattern to match
matchstringnoprefixprefix or exact match
methodsstring[]noallHTTP methods this route applies to
headersmapnoHeader conditions (all must match)
priorityintegerno0Higher priority wins when multiple routes match
strip_pathbooleannofalseParsed and linted, but not applied by the live request handlers
upstreamstringnoParsed and linted, but not used for live provider selection
chainChainEntry[]noPer-route policy chain (overrides global)

Route resolution

For Chat Completions and Responses requests, the gateway:

  1. Collects routes whose normalized path, method, and headers all match.
  2. Sorts them by priority descending. For equal priorities, the first declared route wins.
  3. Uses the matched route's chain when one is configured.
  4. Uses the global chain when no route matches or the matched route omits chain.

Both live handlers invoke route resolution with POST, so a route restricted to another method does not match. Route matching does not alter provider routing or the forwarded path.

Separate chains per endpoint

pack:
name: multi-endpoint
version: 1.0.0
enabled: true
providers:
targets:
- id: openai-primary
provider: openai
model: gpt-5.4-mini
secret_key_ref:
env: KEEPTRUSTS_OPENAI_API_KEY
routes:
- name: chat-secured
path: "/v1/chat/completions"
match: exact
chain:
- prompt-injection
- pii-detector
- quality-scorer
- name: responses-audited
path: "/v1/responses"
match: exact
chain:
- audit-logger
policies:
chain:
- audit-logger
- prompt-injection
- pii-detector
- quality-scorer
policy:
audit-logger: {}
prompt-injection: {}
pii-detector:
action: redact
quality-scorer:
thresholds:
min_aggregate: 0.8

Method conditions

The schema permits a methods list, but the two handlers that perform route resolution are both POST endpoints. Use POST or omit methods; a route for GET /v1/models, for example, is accepted by the parser but is never resolved by that handler.

Header-based routing

pack:
name: config-routes-and-consumers-routes-5
version: 1.0.0
enabled: true
providers:
targets:
- id: openai-primary
provider: openai
model: gpt-5.4-mini
secret_key_ref:
env: KEEPTRUSTS_OPENAI_API_KEY
policies:
chain:
- audit-logger
- prompt-injection
- pii-detector
- dlp-filter
policy:
audit-logger: {}
prompt-injection: {}
pii-detector:
action: redact
dlp-filter:
action: block
routes:
- name: engineering-route
path: "/v1/chat/completions"
match: exact
headers:
X-Team: engineering
chain:
- audit-logger
priority: 10
- name: compliance-route
path: "/v1/chat/completions"
match: exact
headers:
X-Team: compliance
chain:
- prompt-injection
- pii-detector
- dlp-filter
priority: 10
- name: default-route
path: "/v1/chat/completions"
match: exact
chain:
- audit-logger
priority: 0

Parsed-only routing fields

upstream and strip_path are present in the route schema and lint rules, but the live Chat Completions and Responses handlers use only the resolved chain. The server does not read Route.upstream and does not call the route path-rewrite helper. Leave both fields unset until runtime support is implemented.

Consumer groups

The consumer_groups: section identifies API consumers by a presented key. For Chat Completions and Responses requests, a matched group can replace the policy chain and enforce an in-memory max_requests window on that gateway instance.

The schema also accepts rate_limit.max_tokens and group-level upstream, but the live handlers do not consume those values. Do not rely on them for token quotas or provider selection.

Basic consumer group

consumer_groups:
key_header: "Authorization"
groups:
- name: "enterprise"
api_keys:
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
rate_limit:
max_requests: 1000
window_seconds: 60

Full consumer group reference

consumer_groups:
key_header: "Authorization" # header to extract the API key from (default)
groups:
- name: "enterprise"
api_keys: # SHA-256 hashes of permitted keys
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
rate_limit:
max_requests: 1000
window_seconds: 60
chain: # per-group chain override (replaces global)
- "audit-logger"
- name: "free-tier"
api_keys:
- "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
rate_limit:
max_requests: 10
window_seconds: 60

Consumer group fields

FieldTypeRequiredDefaultDescription
key_headerstringno"Authorization"Request header containing the API key
groups[].namestringyesGroup name for logging and diagnostics
groups[].api_keysstring[]yesSHA-256 hex hashes of valid API keys
groups[].rate_limit.max_requestsintegernoLive in-memory request limit per group and gateway instance for Chat Completions and Responses
groups[].rate_limit.max_tokensintegernoParsed, but not enforced by the live handlers
groups[].rate_limit.window_secondsintegeryes (if rate_limit)Rate limit window
groups[].chainChainEntry[]noOverride the policy chain for this group
groups[].upstreamstringnoParsed, but not used for live provider selection

How key matching works

  1. The gateway extracts the value from key_header
  2. When key_header is Authorization, strips the Bearer prefix if present
  3. Computes the SHA-256 hash
  4. Looks up the hash in the consumer group index
  5. For Chat Completions and Responses, applies the group's max_requests limit and uses its chain when configured
  6. If no group matches, uses the route chain when configured, otherwise the global chain

For any other request family, the current handlers do not resolve consumer groups.

Generating key hashes

echo -n "my-secret-api-key" | shasum -a 256 | cut -d' ' -f1
# → 325ededd6c3b9988f623c7f964abb9b016b76b0f8b3474df0f7d7c23b941381f

Tiered access example

pack:
name: "tiered-access"
version: "1.0.0"
enabled: true

providers:
targets:
- id: "openai-primary"
provider: "openai"
model: "gpt-5.4-mini"
secret_key_ref:
env: "KEEPTRUSTS_OPENAI_API_KEY"

consumer_groups:
key_header: "Authorization"
groups:
- name: "enterprise"
api_keys:
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
rate_limit:
max_requests: 5000
window_seconds: 3600
chain:
- "audit-logger"
- name: "professional"
api_keys:
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
rate_limit:
max_requests: 500
window_seconds: 3600
- name: "free-tier"
api_keys:
- "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
rate_limit:
max_requests: 20
window_seconds: 3600
chain:
- "prompt-injection"
- "pii-detector"
- "quality-scorer"

policies:
chain:
- "prompt-injection"
- "pii-detector"
- "quality-scorer"
- "audit-logger"

Combining routes and consumer groups

For Chat Completions and Responses, the gateway resolves both a matching route and a consumer group. A configured consumer-group chain takes precedence over a route chain; a route chain takes precedence over the global chain. Consumer and route upstream values do not participate in provider selection.

pack:
name: "combined-routing"
version: "1.0.0"
enabled: true

providers:
targets:
- id: "openai-primary"
provider: "openai"
model: "gpt-5.4-mini"
secret_key_ref:
env: "KEEPTRUSTS_OPENAI_API_KEY"

routes:
- name: "responses-audited"
path: "/v1/responses"
match: exact
chain:
- "audit-logger"

consumer_groups:
groups:
- name: "internal"
api_keys: ["dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"]
rate_limit:
max_requests: 10000
window_seconds: 3600
chain:
- "prompt-injection"
- "pii-detector"

policies:
chain:
- "prompt-injection"
- "pii-detector"
- "quality-scorer"
- "audit-logger"

Next steps