zuplo 7.2.3 → 7.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/docs/ai-gateway/integrations/ai-sdk.mdx +3 -2
  2. package/docs/ai-gateway/integrations/claude-code.mdx +3 -2
  3. package/docs/ai-gateway/integrations/codex.mdx +7 -5
  4. package/docs/ai-gateway/integrations/goose.mdx +4 -3
  5. package/docs/ai-gateway/integrations/langchain.mdx +3 -3
  6. package/docs/ai-gateway/integrations/openai.mdx +3 -3
  7. package/docs/ai-gateway/policies/overview.mdx +3 -17
  8. package/docs/ai-gateway/universal-api.mdx +4 -3
  9. package/docs/caching/custom-caching-policy.mdx +1 -1
  10. package/docs/caching/gateway-caching.mdx +3 -3
  11. package/docs/caching/overview.mdx +10 -10
  12. package/docs/dedicated/akamai/ai-powered-applications.mdx +2 -2
  13. package/docs/dev-portal/zudoku/configuration/search.md +5 -0
  14. package/docs/dev-portal/zudoku/openapi-extensions/x-mcp-server.md +30 -0
  15. package/docs/policies/_index.md +12 -7
  16. package/docs/policies/ai-gateway-auth-v2-inbound/doc.md +168 -0
  17. package/docs/policies/ai-gateway-auth-v2-inbound/intro.md +10 -0
  18. package/docs/policies/ai-gateway-auth-v2-inbound/schema.json +74 -0
  19. package/docs/policies/ai-gateway-configuration-executor-v2-inbound/doc.md +442 -0
  20. package/docs/policies/ai-gateway-configuration-executor-v2-inbound/intro.md +14 -0
  21. package/docs/policies/ai-gateway-configuration-executor-v2-inbound/schema.json +60 -0
  22. package/docs/policies/ai-gateway-configuration-loader-v2-inbound/doc.md +105 -0
  23. package/docs/policies/ai-gateway-configuration-loader-v2-inbound/intro.md +6 -0
  24. package/docs/policies/ai-gateway-configuration-loader-v2-inbound/schema.json +60 -0
  25. package/docs/policies/ai-gateway-dlp-inbound/doc.md +127 -0
  26. package/docs/policies/ai-gateway-dlp-inbound/intro.md +5 -0
  27. package/docs/policies/ai-gateway-dlp-inbound/schema.json +4050 -0
  28. package/docs/policies/ai-gateway-fallback-model-v2-inbound/doc.md +10 -2
  29. package/docs/policies/ai-gateway-fallback-model-v2-inbound/intro.md +2 -2
  30. package/docs/policies/ai-gateway-fallback-model-v2-inbound/schema.json +22 -8
  31. package/docs/policies/ai-gateway-metering-v2-inbound/doc.md +19 -16
  32. package/docs/policies/ai-gateway-metering-v2-inbound/intro.md +9 -0
  33. package/docs/policies/ai-gateway-metering-v2-inbound/schema.json +20 -24
  34. package/docs/policies/ai-gateway-model-filtering-v2-inbound/doc.md +6 -5
  35. package/docs/policies/ai-gateway-model-filtering-v2-inbound/intro.md +2 -2
  36. package/docs/policies/ai-gateway-model-filtering-v2-inbound/schema.json +17 -3
  37. package/docs/policies/ai-gateway-semantic-cache-v2-inbound/doc.md +72 -0
  38. package/docs/policies/ai-gateway-semantic-cache-v2-inbound/intro.md +9 -0
  39. package/docs/policies/ai-gateway-semantic-cache-v2-inbound/schema.json +120 -0
  40. package/docs/policies/akamai-ai-firewall-v2-inbound/doc.md +87 -0
  41. package/docs/policies/akamai-ai-firewall-v2-inbound/intro.md +10 -0
  42. package/docs/policies/{akamai-ai-firewall → akamai-ai-firewall-v2-inbound}/schema.json +36 -9
  43. package/docs/policies/akamai-firewall-for-ai-inbound/schema.json +1 -0
  44. package/docs/policies/akamai-firewall-for-ai-outbound/schema.json +1 -0
  45. package/docs/policies/amberflo-metering-inbound/schema.json +1 -0
  46. package/docs/policies/api-key-inbound/schema.json +1 -0
  47. package/docs/policies/audit-log-inbound/schema.json +1 -0
  48. package/docs/policies/auth0-jwt-auth-inbound/schema.json +1 -0
  49. package/docs/policies/authzen-inbound/schema.json +1 -0
  50. package/docs/policies/axiomatics-authz-inbound/schema.json +1 -0
  51. package/docs/policies/basic-auth-inbound/schema.json +1 -0
  52. package/docs/policies/bot-detection-inbound/schema.json +1 -0
  53. package/docs/policies/brownout-inbound/schema.json +1 -0
  54. package/docs/policies/caching-inbound/schema.json +1 -0
  55. package/docs/policies/cdn-cache-control-outbound/schema.json +1 -0
  56. package/docs/policies/change-method-inbound/schema.json +1 -0
  57. package/docs/policies/clear-headers-inbound/schema.json +1 -0
  58. package/docs/policies/clear-headers-outbound/schema.json +1 -0
  59. package/docs/policies/clerk-jwt-auth-inbound/schema.json +1 -0
  60. package/docs/policies/cognito-jwt-auth-inbound/schema.json +1 -0
  61. package/docs/policies/comet-opik-tracing-v2-inbound/doc.md +78 -0
  62. package/docs/policies/comet-opik-tracing-v2-inbound/intro.md +10 -0
  63. package/docs/policies/{comet-opik-tracing-inbound → comet-opik-tracing-v2-inbound}/schema.json +40 -5
  64. package/docs/policies/complex-rate-limit-inbound/schema.json +1 -0
  65. package/docs/policies/composite-inbound/schema.json +1 -0
  66. package/docs/policies/composite-outbound/schema.json +1 -0
  67. package/docs/policies/curity-phantom-token-inbound/schema.json +1 -0
  68. package/docs/policies/data-loss-prevention-inbound/doc.md +22 -6
  69. package/docs/policies/data-loss-prevention-inbound/schema.json +10 -1
  70. package/docs/policies/data-loss-prevention-outbound/doc.md +23 -6
  71. package/docs/policies/data-loss-prevention-outbound/schema.json +10 -1
  72. package/docs/policies/firebase-jwt-inbound/schema.json +1 -0
  73. package/docs/policies/formdata-to-json-inbound/schema.json +1 -0
  74. package/docs/policies/galileo-tracing-v2-inbound/doc.md +72 -0
  75. package/docs/policies/galileo-tracing-v2-inbound/intro.md +8 -0
  76. package/docs/policies/{galileo-tracing-inbound → galileo-tracing-v2-inbound}/schema.json +40 -5
  77. package/docs/policies/geo-filter-inbound/schema.json +1 -0
  78. package/docs/policies/graphql-analytics-outbound/schema.json +1 -0
  79. package/docs/policies/graphql-cache-inbound/schema.json +1 -0
  80. package/docs/policies/graphql-complexity-limit-inbound/schema.json +1 -0
  81. package/docs/policies/graphql-disable-introspection-inbound/schema.json +1 -0
  82. package/docs/policies/graphql-introspection-filter-outbound/schema.json +1 -0
  83. package/docs/policies/http-deprecation-outbound/schema.json +1 -0
  84. package/docs/policies/ip-address-restriction-inbound/schema.json +1 -0
  85. package/docs/policies/jwt-scopes-inbound/schema.json +1 -0
  86. package/docs/policies/ldap-auth-inbound/schema.json +1 -0
  87. package/docs/policies/mcp-auth0-oauth-inbound/schema.json +1 -0
  88. package/docs/policies/mcp-capability-filter-inbound/schema.json +1 -0
  89. package/docs/policies/mcp-clerk-oauth-inbound/schema.json +1 -0
  90. package/docs/policies/mcp-cognito-oauth-inbound/schema.json +1 -0
  91. package/docs/policies/mcp-entra-oauth-inbound/schema.json +1 -0
  92. package/docs/policies/mcp-google-oauth-inbound/schema.json +1 -0
  93. package/docs/policies/mcp-keycloak-oauth-inbound/schema.json +1 -0
  94. package/docs/policies/mcp-logto-oauth-inbound/schema.json +1 -0
  95. package/docs/policies/mcp-oauth-inbound/schema.json +1 -0
  96. package/docs/policies/mcp-okta-oauth-inbound/schema.json +1 -0
  97. package/docs/policies/mcp-onelogin-oauth-inbound/schema.json +1 -0
  98. package/docs/policies/mcp-ping-oauth-inbound/schema.json +1 -0
  99. package/docs/policies/mcp-token-exchange-inbound/schema.json +1 -0
  100. package/docs/policies/mcp-workos-oauth-inbound/schema.json +1 -0
  101. package/docs/policies/mock-api-inbound/schema.json +1 -0
  102. package/docs/policies/moesif-inbound/schema.json +1 -0
  103. package/docs/policies/monetization-inbound/schema.json +1 -0
  104. package/docs/policies/mtls-auth-inbound/schema.json +1 -0
  105. package/docs/policies/okta-fga-authz-inbound/schema.json +1 -0
  106. package/docs/policies/okta-jwt-auth-inbound/schema.json +1 -0
  107. package/docs/policies/open-id-jwt-auth-inbound/schema.json +1 -0
  108. package/docs/policies/openfga-authz-inbound/schema.json +1 -0
  109. package/docs/policies/openmeter-inbound/schema.json +1 -0
  110. package/docs/policies/prompt-injection-outbound/schema.json +1 -0
  111. package/docs/policies/propel-auth-jwt-inbound/schema.json +1 -0
  112. package/docs/policies/query-param-to-header-inbound/schema.json +1 -0
  113. package/docs/policies/quota-inbound/schema.json +1 -0
  114. package/docs/policies/rate-limit-inbound/schema.json +1 -0
  115. package/docs/policies/readme-metrics-inbound/schema.json +1 -0
  116. package/docs/policies/remove-headers-inbound/schema.json +1 -0
  117. package/docs/policies/remove-headers-outbound/schema.json +1 -0
  118. package/docs/policies/remove-query-params-inbound/schema.json +1 -0
  119. package/docs/policies/replace-string-outbound/schema.json +1 -0
  120. package/docs/policies/request-size-limit-inbound/schema.json +1 -0
  121. package/docs/policies/request-validation-inbound/schema.json +1 -0
  122. package/docs/policies/require-origin-inbound/schema.json +1 -0
  123. package/docs/policies/require-user-claims-inbound/schema.json +1 -0
  124. package/docs/policies/secret-masking-outbound/schema.json +1 -0
  125. package/docs/policies/semantic-cache-inbound/schema.json +3 -2
  126. package/docs/policies/set-body-inbound/schema.json +1 -0
  127. package/docs/policies/set-headers-inbound/schema.json +1 -0
  128. package/docs/policies/set-headers-outbound/schema.json +1 -0
  129. package/docs/policies/set-query-params-inbound/schema.json +1 -0
  130. package/docs/policies/set-status-outbound/schema.json +1 -0
  131. package/docs/policies/set-upstream-api-key-inbound/schema.json +1 -0
  132. package/docs/policies/sleep-inbound/schema.json +1 -0
  133. package/docs/policies/stripe-webhook-verification-inbound/schema.json +1 -0
  134. package/docs/policies/supabase-jwt-auth-inbound/schema.json +1 -0
  135. package/docs/policies/traffic-splitting-inbound/schema.json +1 -0
  136. package/docs/policies/upstream-aws-federated-auth-inbound/schema.json +1 -0
  137. package/docs/policies/upstream-aws-service-auth-inbound/schema.json +1 -0
  138. package/docs/policies/upstream-azure-ad-service-auth-inbound/schema.json +1 -0
  139. package/docs/policies/upstream-firebase-admin-auth-inbound/schema.json +1 -0
  140. package/docs/policies/upstream-firebase-user-auth-inbound/schema.json +1 -0
  141. package/docs/policies/upstream-gcp-federated-auth-inbound/schema.json +1 -0
  142. package/docs/policies/upstream-gcp-jwt-inbound/schema.json +1 -0
  143. package/docs/policies/upstream-gcp-service-auth-inbound/schema.json +1 -0
  144. package/docs/policies/upstream-oauth-client-credentials-inbound/schema.json +1 -0
  145. package/docs/policies/upstream-zuplo-jwt-auth-inbound/schema.json +1 -0
  146. package/docs/policies/validate-json-schema-inbound/schema.json +1 -0
  147. package/docs/policies/web-bot-auth-inbound/schema.json +1 -0
  148. package/docs/policies/xml-to-json-outbound/schema.json +1 -0
  149. package/package.json +5 -5
  150. package/docs/ai-gateway/policies/akamai-ai-firewall.mdx +0 -122
  151. package/docs/ai-gateway/policies/authentication.mdx +0 -43
  152. package/docs/ai-gateway/policies/comet-opik-tracing.mdx +0 -177
  153. package/docs/ai-gateway/policies/fallback-model.mdx +0 -40
  154. package/docs/ai-gateway/policies/galileo-tracing.mdx +0 -161
  155. package/docs/ai-gateway/policies/metering.mdx +0 -47
  156. package/docs/ai-gateway/policies/model-filtering.mdx +0 -49
  157. package/docs/ai-gateway/policies/semantic-cache.mdx +0 -48
@@ -44,8 +44,9 @@ the app you have configured in Zuplo.
44
44
  Models are referenced as `providerName/model`, where `providerName` is the
45
45
  provider name configured in your gateway. By default an app can reach any model
46
46
  offered by the providers configured for the Zuplo project. To limit it to a
47
- curated set, add the [Model Filtering](../policies/model-filtering.mdx) policy
48
- to the app—it applies separate rules to completions (`generateText`,
47
+ curated set, add the
48
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx)
49
+ policy to the app—it applies separate rules to completions (`generateText`,
49
50
  `streamText`) and embeddings (`embed`), and rejects a capability it doesn't
50
51
  configure.
51
52
 
@@ -69,5 +69,6 @@ ANTHROPIC_MODEL=anthropic/claude-sonnet-4-5-20250929
69
69
  ANTHROPIC_SMALL_FAST_MODEL=anthropic/claude-haiku-4-5
70
70
  ```
71
71
 
72
- The app's [Model Filtering](../policies/model-filtering.mdx) policy controls
73
- which models the app may use.
72
+ The app's
73
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx)
74
+ policy controls which models the app may use.
@@ -83,14 +83,16 @@ codex --config model_provider="zuplo"
83
83
 
84
84
  ### Choosing a model
85
85
 
86
- The app's [Model Filtering](../policies/model-filtering.mdx) policy controls
87
- which models the app may use. Codex names the model as `providerName/model`,
88
- where `providerName` is the provider name configured in your gateway:
86
+ The app's
87
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx)
88
+ policy controls which models the app may use. Codex names the model as
89
+ `providerName/model`, where `providerName` is the provider name configured in
90
+ your gateway:
89
91
 
90
92
  ```bash
91
93
  codex --config model_provider="zuplo" --model "openai/gpt-5"
92
94
  ```
93
95
 
94
96
  A request with no model, or a model without that prefix, gets a `400`. Adding
95
- [Model Filtering](../policies/model-filtering.mdx) with an allow list also
96
- supplies a default, letting requests omit the model.
97
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx) with
98
+ an allow list also supplies a default, letting requests omit the model.
@@ -65,9 +65,10 @@ configuration approaches depending on which version you choose.
65
65
 
66
66
  :::note
67
67
 
68
- The app's [Model Filtering](../policies/model-filtering.mdx) policy controls
69
- which models the app may use, so the model you enter here must be one that
70
- policy allows.
68
+ The app's
69
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx)
70
+ policy controls which models the app may use, so the model you enter here must
71
+ be one that policy allows.
71
72
 
72
73
  :::
73
74
 
@@ -77,6 +77,6 @@ Always name the model as `providerName/model`, where `providerName` is the
77
77
  provider name configured in your gateway. The gateway needs the prefix to know
78
78
  which provider to route to, and a request with no model, or a model without that
79
79
  prefix, gets a `400`. Adding the
80
- [Model Filtering](../policies/model-filtering.mdx) policy restricts an app to
81
- certain models, and an allow list also supplies a default so requests may omit
82
- the model.
80
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx)
81
+ policy restricts an app to certain models, and an allow list also supplies a
82
+ default so requests may omit the model.
@@ -45,9 +45,9 @@ Always name the model as `providerName/model`, where `providerName` is the
45
45
  provider name configured in your gateway. The gateway needs the prefix to know
46
46
  which provider to route to, and a request with no model, or a model without that
47
47
  prefix, gets a `400`. Adding the
48
- [Model Filtering](../policies/model-filtering.mdx) policy restricts an app to
49
- certain models, and an allow list also supplies a default so requests may omit
50
- the model.
48
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx)
49
+ policy restricts an app to certain models, and an allow list also supplies a
50
+ default so requests may omit the model.
51
51
 
52
52
  ```typescript
53
53
  import OpenAI from "openai";
@@ -4,25 +4,11 @@ sidebar_label: Overview
4
4
  description: Every policy an AI Gateway app can run, and what each one does.
5
5
  ---
6
6
 
7
+ import policies from "../../../policies.ui.json";
8
+
7
9
  The gateway's `config/policies.json` declares which policies apps may use, and
8
10
  each app picks from that menu in the order it wants. See
9
11
  [Policy Chains](../policy-chains.mdx) for how a chain executes and how options
10
12
  and secrets are inherited.
11
13
 
12
- | Policy | What it does |
13
- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
14
- | [API key authentication](./authentication.mdx) | Requires an app API key and resolves the calling app from it |
15
- | [Model Filtering](./model-filtering.mdx) | Restricts the app to an allow list or block list of models, and supplies the default model |
16
- | [Fallback Model](./fallback-model.mdx) | Adds a backup model for provider errors and timeouts, and a cheaper model for when a budget runs out |
17
- | [Budgets and Costs](./metering.mdx) | Records usage and enforces the app's budgets for spend, tokens, and requests |
18
- | [Semantic cache](./semantic-cache.mdx) | Returns a cached response when a new prompt is close enough to one already seen |
19
- | [Akamai AI Firewall](./akamai-ai-firewall.mdx) | Scans prompts and completions with your Akamai configuration and blocks what it denies |
20
- | [Comet Opik tracing](./comet-opik-tracing.mdx) | Sends a trace of each request and response to Comet Opik |
21
- | [Galileo tracing](./galileo-tracing.mdx) | Sends a trace of each request and response to Galileo |
22
- | [Configuration Executor](../policy-chains.mdx#configuration-executor) | Loads the app's configuration and runs its chain—this is what makes app chains work |
23
-
24
- The Configuration Executor and its companion Configuration Loader sit on the
25
- gateway's route rather than in an app's chain. API key authentication runs in an
26
- app's chain and protects that app alone. Any
27
- [custom policy](../custom-policies.mdx) you declare joins the menu alongside
28
- these.
14
+ <PolicyOverview policies={policies} products={["ai-gateway"]} />
@@ -54,9 +54,10 @@ console.log(response.choices[0].message.content);
54
54
 
55
55
  :::tip
56
56
 
57
- If the app's [Model Filtering](./policies/model-filtering.mdx) policy has an
58
- allow list, a request that omits `model` uses the first model in the list—so
59
- clients that can't set a model still work.
57
+ If the app's
58
+ [Model Filtering](../policies/ai-gateway-model-filtering-v2-inbound.mdx) policy
59
+ has an allow list, a request that omits `model` uses the first model in the
60
+ list—so clients that can't set a model still work.
60
61
 
61
62
  :::
62
63
 
@@ -26,7 +26,7 @@ your row before writing anything.
26
26
  | A different TTL per route, or per response | The [`cacheConfig` function](./dynamic-cache-rules.mdx) |
27
27
  | Purge tags for targeted CDN invalidation | The CDN policy's `tags` option |
28
28
  | Cache GraphQL query results by query and variables | [`graphql-cache-inbound`](../policies/graphql-cache-inbound.mdx) |
29
- | Cache LLM completions by prompt similarity | [`semantic-cache-inbound`](../policies/semantic-cache-inbound.mdx) |
29
+ | Cache LLM completions by prompt similarity | [`ai-gateway-semantic-cache-v2-inbound`](../policies/ai-gateway-semantic-cache-v2-inbound.mdx) |
30
30
  | Store an arbitrary JSON value with a TTL from your own code | [`ZoneCache`](../programmable-api/zone-cache.mdx) |
31
31
 
32
32
  ## When custom code is the right answer
@@ -298,9 +298,9 @@ the traffic they are built for:
298
298
  - [GraphQL Cache](../policies/graphql-cache-inbound.mdx) normalizes a GraphQL
299
299
  document and its variables before hashing, so two semantically identical
300
300
  queries share an entry even when their bodies differ.
301
- - [Semantic Cache](../policies/semantic-cache-inbound.mdx) matches requests by
302
- meaning rather than exact text, which is what makes caching viable in front of
303
- an LLM.
301
+ - [Semantic Cache](../policies/ai-gateway-semantic-cache-v2-inbound.mdx) matches
302
+ requests by meaning rather than exact text, which is what makes caching viable
303
+ in front of an LLM.
304
304
 
305
305
  To cache a fragment of a response rather than all of it, or to drive the cache
306
306
  from your own code, see
@@ -83,16 +83,16 @@ three above it in Zuplo.
83
83
  Find the row that matches the endpoint in front of you. The rows are ordered
84
84
  roughly by how much a hit saves.
85
85
 
86
- | Situation | Layer | Mechanism | Where to read |
87
- | ---------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------- |
88
- | A public catalog endpoint that returns the same body to everyone | CDN edge | `cdn-cache-control-outbound` with an `edge` and a `client` TTL | [Cache at the CDN](./cdn-caching.mdx) |
89
- | An authenticated endpoint whose body is identical for every caller | CDN edge | `cdn-cache-control-outbound` with `client.visibility: "private"` so only the CDN stores it | [Cache at the CDN](./cdn-caching.mdx) |
90
- | A mostly shared response with a small caller-specific slice | Programmable | Cache the shared fragment with the Cache API or `ZoneCache`, fetch only the dynamic part | [Cache part of a response](./partial-response-caching.mdx) |
91
- | A response whose cacheability depends on what it contains (empty results, error bodies, flags) | CDN edge, per response | A `cacheConfig` function that returns TTLs and purge tags for the response in hand | [Per-response cache rules](./dynamic-cache-rules.mdx) |
92
- | Caching rules no built-in policy expresses (a JWT-claim key, a size limit, an upstream TTL) | Programmable | A custom inbound and outbound policy pair built on the Cache API | [Build a custom caching policy](./custom-caching-policy.mdx) |
93
- | Identical responses served to many callers, with no CDN in front of the gateway | Gateway | `caching-inbound` with an `expirationSecondsTtl` | [Cache at the gateway](./gateway-caching.mdx) |
94
- | A GraphQL query repeated across callers, where the cache key is the query and its variables | Gateway | `graphql-cache-inbound` | [GraphQL Cache policy](../policies/graphql-cache-inbound.mdx) |
95
- | An LLM prompt worded differently each time but asking the same question | Gateway | `semantic-cache-inbound`, which matches on prompt similarity rather than an exact key | [Semantic Cache policy](../policies/semantic-cache-inbound.mdx) |
86
+ | Situation | Layer | Mechanism | Where to read |
87
+ | ---------------------------------------------------------------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
88
+ | A public catalog endpoint that returns the same body to everyone | CDN edge | `cdn-cache-control-outbound` with an `edge` and a `client` TTL | [Cache at the CDN](./cdn-caching.mdx) |
89
+ | An authenticated endpoint whose body is identical for every caller | CDN edge | `cdn-cache-control-outbound` with `client.visibility: "private"` so only the CDN stores it | [Cache at the CDN](./cdn-caching.mdx) |
90
+ | A mostly shared response with a small caller-specific slice | Programmable | Cache the shared fragment with the Cache API or `ZoneCache`, fetch only the dynamic part | [Cache part of a response](./partial-response-caching.mdx) |
91
+ | A response whose cacheability depends on what it contains (empty results, error bodies, flags) | CDN edge, per response | A `cacheConfig` function that returns TTLs and purge tags for the response in hand | [Per-response cache rules](./dynamic-cache-rules.mdx) |
92
+ | Caching rules no built-in policy expresses (a JWT-claim key, a size limit, an upstream TTL) | Programmable | A custom inbound and outbound policy pair built on the Cache API | [Build a custom caching policy](./custom-caching-policy.mdx) |
93
+ | Identical responses served to many callers, with no CDN in front of the gateway | Gateway | `caching-inbound` with an `expirationSecondsTtl` | [Cache at the gateway](./gateway-caching.mdx) |
94
+ | A GraphQL query repeated across callers, where the cache key is the query and its variables | Gateway | `graphql-cache-inbound` | [GraphQL Cache policy](../policies/graphql-cache-inbound.mdx) |
95
+ | An LLM prompt worded differently each time but asking the same question | Gateway | `ai-gateway-semantic-cache-v2-inbound`, which matches on prompt similarity rather than an exact key | [Semantic Cache policy](../policies/ai-gateway-semantic-cache-v2-inbound.mdx) |
96
96
 
97
97
  The intuitive answer is wrong in these cases:
98
98
 
@@ -146,7 +146,7 @@ For more information, see the
146
146
 
147
147
  ## AI Firewall Protection
148
148
 
149
- The [Akamai AI Firewall](../../ai-gateway/policies/akamai-ai-firewall.mdx)
149
+ The [Akamai AI Firewall](../../policies/akamai-ai-firewall-v2-inbound.mdx)
150
150
  provides enterprise-grade security for AI interactions:
151
151
 
152
152
  - **Prompt injection defense** - Detects and blocks attempts to manipulate the
@@ -217,7 +217,7 @@ Deployment options include:
217
217
  Akamai Connected Cloud
218
218
  - [MCP Server Handler](../../handlers/mcp-server.mdx) - Technical documentation
219
219
  for MCP server configuration
220
- - [Akamai AI Firewall](../../ai-gateway/policies/akamai-ai-firewall.mdx) - AI
220
+ - [Akamai AI Firewall](../../policies/akamai-ai-firewall-v2-inbound.mdx) - AI
221
221
  security policy configuration
222
222
  - [Zuplo AI Gateway](../../ai-gateway/introduction.mdx) - Introduction to AI
223
223
  Gateway capabilities
@@ -181,6 +181,11 @@ You can also pass
181
181
  Zudoku's defaults and passed through to Inkeep as-is, so any option Inkeep supports can be used —
182
182
  including ones added after this Dev Portal version was released.
183
183
 
184
+ Dev Portal owns the search modal's open state, so `modalSettings.isOpen` is managed for you. The
185
+ <kbd>⌘</kbd>+<kbd>K</kbd> / <kbd>Ctrl</kbd>+<kbd>K</kbd> shortcut is handled by Zudoku's search
186
+ button as well, which is why Inkeep's own `shortcutKey` is disabled by default. Setting it adds an
187
+ additional shortcut rather than replacing it.
188
+
184
189
  For example, to categorize results into tabs based on their URL:
185
190
 
186
191
  ```typescript
@@ -32,6 +32,7 @@ When using the object form, the following properties are available:
32
32
  | --------- | --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
33
33
  | `name` | `string` | No | Display name used in the generated client configuration snippets. Falls back to the operation `summary`, then `"mcp-server"` |
34
34
  | `version` | `string` | No | Version metadata |
35
+ | `url` | `string` | No | Overrides the endpoint URL shown in the card and install snippets. See [MCP URL resolution](#mcp-url-resolution) |
35
36
  | `tools` | `[Tool Object]` | No | Array of tools provided by the MCP server |
36
37
 
37
38
  Each item in the `tools` array:
@@ -47,6 +48,35 @@ The displayed MCP URL is constructed from the **server URL** of the API and the
47
48
  operation. The server URL comes from the OpenAPI `servers` array (or the operation-level `servers`
48
49
  override if present).
49
50
 
51
+ ### Overriding the URL
52
+
53
+ Set `url` on `x-mcp-server` when the MCP server is not reachable under the documented API server —
54
+ for example when it runs on its own hostname:
55
+
56
+ ```yaml
57
+ servers:
58
+ - url: https://api.example.com
59
+ paths:
60
+ /mcp:
61
+ post:
62
+ summary: My MCP Server
63
+ x-mcp-server:
64
+ name: my-mcp-server
65
+ url: https://mcp.example.com/mcp
66
+ responses:
67
+ "200":
68
+ description: MCP response
69
+ ```
70
+
71
+ The card and every install snippet then use `https://mcp.example.com/mcp` instead of
72
+ `https://api.example.com/mcp`.
73
+
74
+ An absolute `url` (one with a scheme, such as `https://`) replaces the endpoint entirely and is used
75
+ verbatim — it also takes precedence over the server picked in the server dropdown, since it names a
76
+ host of its own. A value without a scheme is treated as a path on the server URL instead, so
77
+ `url: /v2/mcp` resolves to `https://api.example.com/v2/mcp` and still follows server selection.
78
+ Blank values are ignored and the URL falls back to the server URL plus the operation path.
79
+
50
80
  ## Examples
51
81
 
52
82
  ### Boolean shorthand
@@ -4,10 +4,14 @@
4
4
  | --- | --- | --- | --- |
5
5
  | set-query-params-inbound | Add or Set Query Parameters | Adds or sets query parameters on the incoming request. | api-gateway |
6
6
  | set-headers-inbound | Add or Set Request Headers | Adds or sets headers on the incoming request. | api-gateway |
7
- | ai-gateway-fallback-model-v2-inbound | AI Gateway Fallback Model (v2) | Adds failure and quota fallbacks to an existing AI Gateway model selection. Place this policy after AI Gateway Model Filtering (v2). It never creates a model selection, so a misplaced policy cannot bypass filtering. | ai-gateway |
8
- | ai-gateway-metering-v2-inbound | AI Gateway Metering (v2) | Meters AI Gateway v2 usage and enforces app and ancestor usage limits. Limits configured on parent teams or the bucket root are enforced through a server-side hierarchical check. The authentication policy must run before this policy so the app configuration id is available for meter storage and analytics. | ai-gateway |
9
- | ai-gateway-model-filtering-v2-inbound | AI Gateway Model Filtering (v2) | Matches AI Gateway requests against curated allow lists or open block lists, then stores the winning model reference for the route handler. | ai-gateway |
10
- | akamai-ai-firewall | Akamai AI Firewall | Akamai AI Firewall Inbound Policy | ai-gateway |
7
+ | ai-gateway-auth-v2-inbound | AI Gateway Authentication | Authenticates requests to an AI Gateway endpoint with application API keys. Add this policy to an application's `inboundPolicyChain` to require a key for that app only, or place it on the route before the configuration executor to require a key for every application on the route. The policies that follow can read the authenticated application from `request.user` (`sub` is the application name, `data` its metadata), and the application's AI Gateway configuration takes effect for the request. Use `authHeader` and `authScheme` when clients send their app key somewhere other than the default `Authorization: Bearer` header. When the matched route captures an `app_id` path parameter (platform catch-all `/:app_id/(.*)`), this policy also requires `configuration.id === request.params.app_id` and returns 403 on mismatch. | ai-gateway |
8
+ | ai-gateway-configuration-executor-v2-inbound | AI Gateway Configuration Executor | Loads the app configuration for the request (when auth or the configuration loader has not already) and runs the inbound policy chain from that configuration. Place this policy on AI Gateway routes after optional authentication and optional `ai-gateway-configuration-loader-v2-inbound`. When either of those already populated the app-configuration channel, this policy reuses it. Otherwise it loads the configuration with the route's `app_id` path parameter. Applications select from policies pre-declared by the gateway. Applications without a `inboundPolicyChain`, or with an empty chain, run no application-selected policies. Entry options replace the declaration's options as a complete object; omit them to inherit the declaration, including environment-backed credentials. Each occurrence receives a private deep copy of its entry options, so a policy mutating its options cannot corrupt the cached app configuration. | ai-gateway |
9
+ | ai-gateway-configuration-loader-v2-inbound | AI Gateway Configuration Loader | Loads the AI Gateway app configuration for the request into the request-scoped channel and does nothing else. Place this policy on AI Gateway routes before `ai-gateway-configuration-executor-v2-inbound` when you want configuration loading separated from chain execution. When `ai-gateway-auth-v2-inbound` already populated the channel, this policy reuses it. Otherwise it loads the configuration with the route's `app_id` path parameter. If this policy is omitted, the configuration executor still loads configuration itself before running the application chain. | ai-gateway |
10
+ | ai-gateway-fallback-model-v2-inbound | AI Gateway Fallback Model | Adds failure and quota fallbacks to an existing AI Gateway model selection. Place this policy after AI Gateway Model Filtering. It never creates a model selection, so a misplaced policy cannot bypass filtering. | ai-gateway |
11
+ | ai-gateway-metering-v2-inbound | AI Gateway Metering | Meters AI Gateway usage and enforces app and ancestor usage limits. Limits configured on parent teams or the bucket root are enforced through a server-side hierarchical check. The authentication policy must run before this policy so the app configuration id is available for meter storage and analytics. | ai-gateway |
12
+ | ai-gateway-model-filtering-v2-inbound | AI Gateway Model Filtering | Matches AI Gateway requests against curated allow lists or open block lists, then stores the winning model reference for the route handler. | ai-gateway |
13
+ | ai-gateway-semantic-cache-v2-inbound | AI Gateway Semantic Cache | AI Gateway Semantic Cache policy. This inbound policy looks up the semantic cache on entry and, on a miss, registers a response-sending hook to write the upstream response back into the cache. Caching parameters (semanticTolerance, expirationSecondsTtl, namespace, recentMessageCount) come from the policy options, and presence in the route's chain is what enables it. An id from the authenticated app configuration always provides the cache namespace so application-supplied options cannot cross tenant partitions. The cache key covers the system prompt plus the last `recentMessageCount` messages (default 1) — applied when storing and when matching — so multi-turn conversations can hit entries cached from earlier, shorter ones. Cache outcomes are reported on the response via the RFC 9211 `Cache-Status` header under the cache name `zp-aigw-sem-cache` (hit: `zp-aigw-sem-cache; hit; detail="similarity=0.93"`; miss: `zp-aigw-sem-cache; fwd=miss; stored`). Responses also include the `x-ai-gateway-cache: HIT\|MISS` and `x-ai-gateway-cache-similarity` headers. | ai-gateway |
14
+ | akamai-ai-firewall-v2-inbound | Akamai AI Firewall | Akamai AI Firewall Inbound Policy | ai-gateway |
11
15
  | akamai-firewall-for-ai-outbound | Akamai Firewall for AI | Inspects each upstream response with Akamai's Firewall for AI detect API and replaces the response with a `403 Forbidden` if Akamai returns a `deny` rule. Useful behind AI-powered APIs to filter unsafe completions, sensitive data exposure, and toxic content before they reach the client. The body, headers, URL, and query string sent to Akamai are configurable; by default only the response body is captured. Bodies are read from a clone so the client still receives the original. | api-gateway |
12
16
  | akamai-firewall-for-ai-inbound | Akamai Firewall for AI | Inspects each incoming request with Akamai's Firewall for AI detect API and blocks the request if Akamai returns a `deny` rule. Useful in front of AI-powered APIs to filter prompt injection, jailbreaks, and other unsafe inputs before they reach the model. The body, headers, URL, and query string sent to Akamai are configurable; by default only the request body is captured. Bodies are read from a clone so the upstream handler still sees the original. | api-gateway |
13
17
  | amberflo-metering-inbound | Amberflo Metering / Billing | Amberflo is a usage metering and billing service. This policy allows you to send metering calls for each API to their meter ingest endpoint. | api-gateway |
@@ -26,7 +30,7 @@
26
30
  | clear-headers-inbound | Clear Request Headers | Removes all headers from the incoming request except for those in the exclude list. | api-gateway |
27
31
  | clear-headers-outbound | Clear Response Headers | Removes all headers from the response except for those in the exclude list. | api-gateway |
28
32
  | clerk-jwt-auth-inbound | Clerk JWT Auth | Authenticate users using Clerk issued JWT tokens. | api-gateway |
29
- | comet-opik-tracing-inbound | Comet Opik Tracing | Comet Opik Tracing Inbound Policy | ai-gateway |
33
+ | comet-opik-tracing-v2-inbound | Comet Opik Tracing | Comet Opik Tracing Inbound Policy | ai-gateway |
30
34
  | complex-rate-limit-inbound | Complex Rate Limiting | The Complex Rate Limiting policy is an advanced rate limiting policy that let's you set rate limits based on custom counters (not just requests) | api-gateway |
31
35
  | composite-inbound | Composite Inbound (Group Policies) | Creates a composite, or group policy - composed of other inbound policies. For reuse across routes. | api-gateway |
32
36
  | composite-outbound | Composite Outbound (Group Policies) | Creates a composite, or group policy - composed of other outbound policies. For reuse across routes. | api-gateway |
@@ -35,9 +39,10 @@
35
39
  | custom-code-outbound | Custom Code Outbound | A custom outbound response policy. | api-gateway |
36
40
  | data-loss-prevention-outbound | Data Loss Prevention | Scans the upstream response body for sensitive data — PII, secrets, and financial identifiers — using an extensible catalog of built-in recognizers plus any custom patterns, and takes a configurable action when a match is found. The action is one of `mask` (redact matches before returning the response), `block` (replace the response with a `422` listing the detected entity names only), or `log` (record a warning and return unchanged). Only text content types are inspected; binary bodies pass through untouched, and the body is read from a clone so the client still receives the original stream. | api-gateway |
37
41
  | data-loss-prevention-inbound | Data Loss Prevention | Scans the incoming request body for sensitive data — PII, secrets, and financial identifiers — using an extensible catalog of built-in recognizers plus any custom patterns, and takes a configurable action when a match is found. The action is one of `mask` (redact matches before forwarding the request), `block` (reject with a `422` listing the detected entity names only), or `log` (record a warning and forward unchanged). Only text content types are inspected; binary bodies pass through untouched, and the body is read from a clone so the upstream still receives the original stream. | api-gateway |
42
+ | ai-gateway-dlp-inbound | Data Loss Prevention (DLP) | Data Loss Prevention (DLP) Inbound Policy for the AI Gateway | ai-gateway |
38
43
  | firebase-jwt-inbound | Firebase JWT Auth | Authenticate users using Firebase issued JWT tokens. | api-gateway |
39
44
  | formdata-to-json-inbound | Form Data to JSON | Converts form data in the incoming request to JSON. | api-gateway |
40
- | galileo-tracing-inbound | Galileo Tracing | Galileo Tracing Inbound Policy | ai-gateway |
45
+ | galileo-tracing-v2-inbound | Galileo Tracing | Galileo Tracing Inbound Policy | ai-gateway |
41
46
  | geo-filter-inbound | Geo-location filtering | Block requests based on geo-location parameters: country, region code, and ASN | api-gateway |
42
47
  | graphql-analytics-outbound | GraphQL Analytics | Reports GraphQL errors returned in response bodies to Zuplo's GraphQL analytics. GraphQL servers following the standard Apollo / graphql-yoga pattern return `200 OK` with an `errors[]` array in the body when an operation fails, which HTTP-level analytics alone report as a success — add this policy to a GraphQL route and failed operations show up as failures on the GraphQL dashboard, classified by error type. Each error in `errors[]` is classified from its `extensions.code` following the Apollo Server conventions (`GRAPHQL_PARSE_FAILED` → `syntax`, `GRAPHQL_VALIDATION_FAILED` → `validation`, `UNAUTHENTICATED` / `FORBIDDEN` → `auth`, timeout codes → `timeout`); custom codes can be mapped with `errorCodeClassification`, and anything unrecognized falls back to `defaultErrorClass` (`resolver`). Optionally set `logErrors` to also write a structured warning per errored response. The policy reads up to `maxScanBytes` of the body (128 KiB by default, 5 MiB maximum), scanning it for the `errors` token; a response larger than that is treated as error-free. When the token is found and the body fits, it is parsed and its errors reported. The response always passes through unchanged — the body is read from a clone, and any internal failure is swallowed so reporting can never break the request. The route must be marked `x-graphql: true` in `routes.oas.json` (which enables GraphQL analytics for the route); without the marker the policy logs a warning and does nothing. | api-gateway |
43
48
  | graphql-cache-inbound | GraphQL Cache | Caches GraphQL query responses at the edge so identical queries are served without a round-trip to the origin. Unlike CDN caching that keys on the raw request body, this policy parses the GraphQL document and normalizes it before hashing: insignificant whitespace, field formatting, and fragment layout are collapsed, and variable object keys are sorted. Two requests that are semantically identical therefore share a cache entry even when their bodies differ byte-for-byte. There is no query size or nesting-depth limit. Only `query` operations are cached. Mutations, subscriptions, malformed documents, and non-JSON bodies are forwarded to the origin untouched. Cache hits and misses are reported on the `x-cache` response header, with a short key fingerprint on `x-cache-key`. To avoid serving one user's data to another, requests carrying an `authorization` or `cookie` header are not cached by default. Use `cacheKeyHeaders` to opt into caching them: each listed header's value is included in the cache key, so distinct credentials get distinct cache entries. | api-gateway |
@@ -87,7 +92,7 @@
87
92
  | require-origin-inbound | Require Origin | Sets an allow-list for an origin header | api-gateway |
88
93
  | require-user-claims-inbound | Require User Claims | Authorizes requests by validating claims on the authenticated user (`request.user`) against a configurable rule of `and`/`or` combinators and per-claim `eq`, `in`, and `startsWith` checks. Run it after any authentication policy that populates `request.user` — a JWT auth policy, API key auth, mTLS, and so on — to allow only specific callers (service accounts, OAuth clients, tenants, groups) without writing custom code. Every check fails closed: a missing or non-primitive claim never matches, comparisons are strict and type-sensitive, and requests without an authenticated user receive a 401 response. Denied requests receive a 403 response that does not echo claim values or expected values; the failing checks are written to the request log instead. Validation of the options runs lazily inside the policy constructor, which the runtime caches per policy name. Misconfigured options therefore fail on first use with a customer-facing `ConfigurationError` instead of failing at module load. | api-gateway |
89
94
  | secret-masking-outbound | Secret Masking (deprecated) | Masks common secrets like Zuplo API keys, GitHub tokens, or SSH private key in the response body. | api-gateway |
90
- | semantic-cache-inbound | Semantic Cache | Respond to matched incoming requests with semantically cached content The Semantic Cache Inbound policy caches responses based on semantic similarity of cache keys rather than exact matches. This allows for more flexible caching where similar requests can return cached responses even if the cache key is not exactly the same. The policy uses Large Language Model (LLM) embeddings to determine semantic similarity between cache keys based on a configurable similarity tolerance. Options: - semanticTolerance: The semantic similarity threshold for semantic cache matches (0-1, default: 0.2). Values closer to 0 require higher similarity. Can be overridden by custom functions. - expirationSecondsTtl: The timeout of the cache in seconds (default: 3600, 1 hour). Can be overridden by custom functions. - namespace: Optional namespace to isolate cache entries (default: "default"). Useful for multi-tenant scenarios or different cache contexts. - cacheBy: Determines how cache keys are generated: 'function' for custom logic or 'propertyPath' to extract from JSON body. | ai-gateway |
95
+ | semantic-cache-inbound | Semantic Cache (deprecated) | Respond to matched incoming requests with semantically cached content The Semantic Cache Inbound policy caches responses based on semantic similarity of cache keys rather than exact matches. This allows for more flexible caching where similar requests can return cached responses even if the cache key is not exactly the same. The policy uses Large Language Model (LLM) embeddings to determine semantic similarity between cache keys based on a configurable similarity tolerance. Options: - semanticTolerance: The semantic similarity threshold for semantic cache matches (0-1, default: 0.2). Values closer to 0 require higher similarity. Can be overridden by custom functions. - expirationSecondsTtl: The timeout of the cache in seconds (default: 3600, 1 hour). Can be overridden by custom functions. - namespace: Optional namespace to isolate cache entries (default: "default"). Useful for multi-tenant scenarios or different cache contexts. - cacheBy: Determines how cache keys are generated: 'function' for custom logic or 'propertyPath' to extract from JSON body. | ai-gateway |
91
96
  | set-body-inbound | Set Body | Sets the body of the request in the inbound pipeline - make sure to convert a GET/HEAD request to another method when using this policy. | api-gateway |
92
97
  | set-headers-outbound | Set Headers | Adds or sets headers on the on the outgoing response. | api-gateway |
93
98
  | set-status-outbound | Set Status Code | Sets the status code on the on the outgoing response. | api-gateway |
@@ -0,0 +1,168 @@
1
+ # AI Gateway Authentication
2
+
3
+ The AI Gateway Authentication policy authenticates requests with an AI Gateway
4
+ application API key. After a key is accepted, the calling application is
5
+ identified on `request.user` — `sub` is the application name and `data` its
6
+ metadata, both readable from custom policies — and the application's AI Gateway
7
+ configuration (its selected policy chain, model access, and limits) takes effect
8
+ for the request through the AI Gateway policies later in the route.
9
+
10
+ Use this policy when an application (or every application on a route) must
11
+ present an AI Gateway application API key.
12
+
13
+ A missing or invalid key returns `401 Unauthorized`. A valid key that belongs to
14
+ a different application than the route's `app_id` returns `403 Forbidden`.
15
+
16
+ ## Prerequisites
17
+
18
+ Create the AI Gateway applications and their API keys before calling the
19
+ gateway. Each client must use a key issued for one of those applications.
20
+
21
+ ## Add the policy
22
+
23
+ Declare the policy in `config/policies.json`:
24
+
25
+ ```json
26
+ {
27
+ "policies": [
28
+ {
29
+ "name": "ai-gateway-auth-v2-inbound",
30
+ "policyType": "ai-gateway-auth-v2",
31
+ "handler": {
32
+ "export": "AIGatewayAuthV2InboundPolicy",
33
+ "module": "$import(@zuplo/runtime)",
34
+ "options": {
35
+ "cacheTtlSeconds": 60
36
+ }
37
+ }
38
+ }
39
+ ]
40
+ }
41
+ ```
42
+
43
+ Authentication is optional. Choose where to attach it based on how widely keys
44
+ should be required:
45
+
46
+ ### Per application (app-level)
47
+
48
+ Add the policy to an application's `inboundPolicyChain`. Only that application
49
+ requires an API key; other applications on the same route can omit it. The route
50
+ should run the configuration executor alone so it can load configuration from
51
+ the `app_id` path parameter before the app chain runs:
52
+
53
+ ```json
54
+ {
55
+ "inboundPolicyChain": [
56
+ {
57
+ "name": "ai-gateway-auth-v2-inbound"
58
+ }
59
+ ]
60
+ }
61
+ ```
62
+
63
+ ### Every application on the route (route-level)
64
+
65
+ Add the policy on the route **before** the configuration loader (or before the
66
+ executor on executor-only routes). That requires an API key for every
67
+ application that hits the route:
68
+
69
+ ```json
70
+ {
71
+ "x-zuplo-route": {
72
+ "corsPolicy": "none",
73
+ "handler": {
74
+ "export": "aiGatewayHandlerV2",
75
+ "module": "$import(@zuplo/runtime)",
76
+ "options": {}
77
+ },
78
+ "policies": {
79
+ "inbound": [
80
+ "ai-gateway-auth-v2-inbound",
81
+ "ai-gateway-configuration-loader-v2-inbound",
82
+ "ai-gateway-configuration-executor-v2-inbound"
83
+ ]
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ When auth runs on the route, it loads the app configuration from the key and the
90
+ loader/executor reuse that channel. When auth is omitted from the route (or only
91
+ present in some apps' chains), the loader (or the executor alone) loads
92
+ configuration from the route's `app_id` path parameter instead.
93
+
94
+ > **Protect every public gateway.** Without this policy, the gateway resolves
95
+ > the application from the URL and accepts the request without an application
96
+ > key. Only leave authentication out when another control, such as network
97
+ > isolation, restricts access. Team policy templates can include a locked auth
98
+ > entry so new applications require keys by default.
99
+
100
+ ## Call the gateway
101
+
102
+ By default, clients send the application key as a bearer token:
103
+
104
+ ```bash
105
+ curl https://gateway.example.com/v1/chat/completions \
106
+ --header "Authorization: Bearer YOUR_APP_KEY" \
107
+ --header "Content-Type: application/json" \
108
+ --data '{
109
+ "model": "openai/gpt-5-mini",
110
+ "messages": [{ "role": "user", "content": "Hello" }]
111
+ }'
112
+ ```
113
+
114
+ Authentication scheme matching is case-insensitive. A missing key, an invalid
115
+ scheme, or a key that is not authorized receives a `401 Unauthorized` response.
116
+
117
+ ## Use a custom header
118
+
119
+ Set `authHeader` to accept the key from another header. Set `authScheme` to an
120
+ empty string when the header contains only the key:
121
+
122
+ ```json
123
+ {
124
+ "name": "ai-gateway-auth-v2-inbound",
125
+ "policyType": "ai-gateway-auth-v2",
126
+ "handler": {
127
+ "export": "AIGatewayAuthV2InboundPolicy",
128
+ "module": "$import(@zuplo/runtime)",
129
+ "options": {
130
+ "authHeader": "x-api-key",
131
+ "authScheme": "",
132
+ "cacheTtlSeconds": 60
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ Clients can then call the gateway with:
139
+
140
+ ```bash
141
+ curl https://gateway.example.com/v1/chat/completions \
142
+ --header "x-api-key: YOUR_APP_KEY" \
143
+ --header "Content-Type: application/json" \
144
+ --data '{
145
+ "model": "openai/gpt-5-mini",
146
+ "messages": [{ "role": "user", "content": "Hello" }]
147
+ }'
148
+ ```
149
+
150
+ ## Choose a cache duration
151
+
152
+ `cacheTtlSeconds` controls how long an authentication result can be reused. The
153
+ minimum value is 10 seconds.
154
+
155
+ - Use a shorter duration when key changes must take effect quickly.
156
+ - Use a longer duration to reduce authentication latency and repeated validation
157
+ work.
158
+
159
+ A revoked key can continue to work until its cached result expires.
160
+
161
+ ## Options
162
+
163
+ - `cacheTtlSeconds`: Number of seconds to cache an authentication result.
164
+ Defaults to `10` and must be at least `10`.
165
+ - `authHeader`: Header containing the application key. Defaults to
166
+ `Authorization`.
167
+ - `authScheme`: Scheme before the key. Defaults to `Bearer`. Use `""` for a
168
+ header containing the key without a scheme.
@@ -0,0 +1,10 @@
1
+ The AI Gateway Authentication policy protects an AI Gateway with application API
2
+ keys. It identifies the calling application on `request.user` (`sub` is the
3
+ application name, `data` its metadata) and puts the application's AI Gateway
4
+ configuration into effect for the policies later in the request pipeline.
5
+
6
+ Add it to an application's `inboundPolicyChain` to require a key for that app
7
+ only, or place it on the route before the configuration executor to require a
8
+ key for every application on the route. Clients can send keys with the standard
9
+ `Authorization: Bearer` header or with a custom header and scheme.
10
+ Authentication results can be cached briefly to reduce request latency.
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft-07/schema",
3
+ "$id": "https://cdn.zuplo.com/policies/runtime/schemas/ai-gateway-auth-v2-inbound.json",
4
+ "type": "object",
5
+ "title": "AI Gateway Authentication",
6
+ "isDeprecated": false,
7
+ "isPaidAddOn": false,
8
+ "isEnterprise": false,
9
+ "isInternal": false,
10
+ "isBeta": false,
11
+ "isHidden": false,
12
+ "requiresAI": true,
13
+ "policyType": "ai-gateway-auth-v2",
14
+ "products": ["ai-gateway"],
15
+ "description": "Authenticates requests to an AI Gateway endpoint with application API keys.\n\nAdd this policy to an application's `inboundPolicyChain` to require a key for that app only, or place it on the route before the configuration executor to require a key for every application on the route. The policies that follow can read the authenticated application from `request.user` (`sub` is the application name, `data` its metadata), and the application's AI Gateway configuration takes effect for the request. Use `authHeader` and `authScheme` when clients send their app key somewhere other than the default `Authorization: Bearer` header.\n\nWhen the matched route captures an `app_id` path parameter (platform catch-all `/:app_id/(.*)`), this policy also requires `configuration.id === request.params.app_id` and returns 403 on mismatch.",
16
+ "deprecatedMessage": "",
17
+ "required": ["handler"],
18
+ "properties": {
19
+ "handler": {
20
+ "type": "object",
21
+ "default": {},
22
+ "required": ["export", "module", "options"],
23
+ "properties": {
24
+ "export": {
25
+ "const": "AIGatewayAuthV2InboundPolicy",
26
+ "description": "The name of the exported type"
27
+ },
28
+ "module": {
29
+ "const": "$import(@zuplo/runtime)",
30
+ "description": "The module containing the policy"
31
+ },
32
+ "options": {
33
+ "x-zuplo-policy-type": "ai-gateway-auth-v2",
34
+ "title": "AIGatewayAuthV2InboundPolicyOptions",
35
+ "type": "object",
36
+ "description": "The options for this policy.",
37
+ "additionalProperties": false,
38
+ "required": [],
39
+ "properties": {
40
+ "cacheTtlSeconds": {
41
+ "type": "number",
42
+ "default": 10,
43
+ "minimum": 10,
44
+ "description": "The time to cache authentication results for a particular key. Higher values will decrease latency. Cached results will be valid until the cache expires even in the event the key is deleted, etc."
45
+ },
46
+ "authHeader": {
47
+ "type": "string",
48
+ "default": "Authorization",
49
+ "x-show-example": false,
50
+ "x-advanced": true,
51
+ "description": "The name of the header with the key."
52
+ },
53
+ "authScheme": {
54
+ "type": "string",
55
+ "default": "Bearer",
56
+ "x-show-example": false,
57
+ "x-advanced": true,
58
+ "description": "The scheme used on the header."
59
+ }
60
+ }
61
+ }
62
+ },
63
+ "examples": [
64
+ {
65
+ "export": "AIGatewayAuthV2InboundPolicy",
66
+ "module": "$import(@zuplo/runtime)",
67
+ "options": {
68
+ "cacheTtlSeconds": 10
69
+ }
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ }