Update to Netlify
Snapshot Oct 7, 2026 · 00:02 UTC · version 1.6.0
Collection source: downloaded plugin package. These snapshots do not have a confirmed matching collection source. Differences in file lists alone do not establish changes to the package.
Payment or plan references changed
Instruction wording changed from “Guide for using Netlify AI Gateway to access AI models. Use when adding AI capabilities or selecting/changing AI models. Must be read before choosing a model. Covers supported providers (OpenAI, Anthropic, Google), SDK setup, environment...” to “Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys....”. 189 additional added or edited lines are in the evidence.
Observed in published text. Live prices and checkout terms have not been verified by this change.
Product description
Guide for using Netlify AI Gateway to access AI models. Use when adding AI capabilities or selecting/changing AI models. Must be read before choosing a model. Covers supported providers (OpenAI, Anthropic, Google), SDK setup, environment...
Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys....
Skill instructions
Guide for using Netlify AI Gateway to access AI models. Use when adding AI capabilities or selecting/changing AI models. Must be read before choosing a model. Covers supported providers (OpenAI, Anthropic, Google), SDK setup, environment...
Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys....
Supporting files
[{"relative_path":"LICENSE.txt","size_in_bytes":10776},{"relative_path":"agents/openai.yaml","size_in_bytes":336},{"relative_path":"assets/netlify-small.svg","size_in_bytes":1291},{"relative_path":"assets/netlify.png","size_in_bytes":2686}]
[]
Compare saved observations
Download comparison JSONFull technical diff · 3 changed fields
changed /description
"Guide for using Netlify AI Gateway to access AI models. Use when adding AI capabilities or selecting/changing AI models. Must be read before choosing a model. Covers supported providers (OpenAI, Anthropic, Google), SDK setup, environment variables, and the list of available models."
"Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys. Reach for this when adding an AI feature to a Netlify app — a chatbot, text summarizer, image generator, joke/content generator, form-submission routing or analysis, or any LLM call — or when wiring the OpenAI/Anthropic/Gemini/TypeSafe/OpenRouter SDK into a Netlify Function, choosing which env vars to use, streaming long generations, or debugging why gateway calls fail at build time or return 401."
changed /included_files
[
{
"relative_path": "LICENSE.txt",
"size_in_bytes": 10776
},
{
"relative_path": "agents/openai.yaml",
"size_in_bytes": 336
},
{
"relative_path": "assets/netlify-small.svg",
"size_in_bytes": 1291
},
{
"relative_path": "assets/netlify.png",
"size_in_bytes": 2686
}
][]
changed /skill_md_contents
"---\nname: netlify-ai-gateway\ndescription: Guide for using Netlify AI Gateway to access AI models. Use when adding AI capabilities or selecting/changing AI models. Must be read before choosing a model. Covers supported providers (OpenAI, Anthropic, Google), SDK setup, environment variables, and the list of available models.\n---\n\n# Netlify AI Gateway\n\n> **IMPORTANT:** Only use models listed in the \"Available Models\" section below. AI Gateway does not support every model a provider offers. Using an unsupported model will cause runtime errors.\n\nNetlify AI Gateway provides access to AI models from multiple providers without managing API keys directly. It is available on all Netlify sites.\n\n## How It Works\n\nThe AI Gateway acts as a proxy — you use standard provider SDKs (OpenAI, Anthropic, Google) but point them at Netlify's gateway URL instead of the provider's API. Netlify handles authentication, rate limiting, and monitoring.\n\n## Setup\n\n1. Enable AI on your site in the Netlify UI\n2. The environment variable `OPENAI_BASE_URL` is set automatically by Netlify\n3. Install the provider SDK you want to use\n\nNo provider API keys are needed — Netlify's gateway handles authentication.\n\n## Using OpenAI SDK\n\n```bash\nnpm install openai\n```\n\n```typescript\nimport OpenAI from \"openai\";\n\nconst openai = new OpenAI();\n// OPENAI_BASE_URL is auto-configured — no API key or base URL needed\n\nconst completion = await openai.chat.completions.create({\n model: \"gpt-4o-mini\",\n messages: [{ role: \"user\", content: \"Hello!\" }],\n});\n```\n\n## Using Anthropic SDK\n\n```bash\nnpm install @anthropic-ai/sdk\n```\n\n```typescript\nimport Anthropic from \"@anthropic-ai/sdk\";\n\nconst client = new Anthropic({\n baseURL: Netlify.env.get(\"ANTHROPIC_BASE_URL\"),\n});\n\nconst message = await client.messages.create({\n model: \"claude-sonnet-4-5-20250929\",\n max_tokens: 1024,\n messages: [{ role: \"user\", content: \"Hello!\" }],\n});\n```\n\n## Using Google AI SDK\n\n```bash\nnpm install @google/generative-ai\n```\n\n```typescript\nimport { GoogleGenerativeAI } from \"@google/generative-ai\";\n\nconst genAI = new GoogleGenerativeAI(\"placeholder\");\n// Configure base URL via environment variable\n\nconst model = genAI.getGenerativeModel({ model: \"gemini-2.5-flash\" });\nconst result = await model.generateContent(\"Hello!\");\n```\n\n## In a Netlify Function\n\n```typescript\nimport type { Config, Context } from \"@netlify/functions\";\nimport OpenAI from \"openai\";\n\nexport default async (req: Request, context: Context) => {\n const { prompt } = await req.json();\n const openai = new OpenAI();\n\n const completion = await openai.chat.completions.create({\n model: \"gpt-4o-mini\",\n messages: [{ role: \"user\", content: prompt }],\n });\n\n return Response.json({\n response: completion.choices[0].message.content,\n });\n};\n\nexport const config: Config = {\n path: \"/api/ai\",\n method: \"POST\",\n};\n```\n\n## Environment Variables\n\n| Variable | Provider | Set by |\n|---|---|---|\n| `OPENAI_BASE_URL` | OpenAI | Netlify (automatic) |\n| `ANTHROPIC_BASE_URL` | Anthropic | Netlify (automatic) |\n\nThese are configured automatically when AI is enabled on the site. No manual setup required.\n\n## Local Development\n\nWith `@netlify/vite-plugin` or `netlify dev`, gateway environment variables are injected automatically. The AI Gateway is accessible during local development after the site has been deployed at least once.\n\n## Available Models\n\nFor the list of supported models, see https://docs.netlify.com/build/ai-gateway/overview/.\n""---\nname: netlify-ai-gateway\ndescription: Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys. Reach for this when adding an AI feature to a Netlify app — a chatbot, text summarizer, image generator, joke/content generator, form-submission routing or analysis, or any LLM call — or when wiring the OpenAI/Anthropic/Gemini/TypeSafe/OpenRouter SDK into a Netlify Function, choosing which env vars to use, streaming long generations, or debugging why gateway calls fail at build time or return 401.\n---\n\n# Netlify AI Gateway\n\nCall AI models from Netlify compute using the provider's official SDK. The gateway injects provider credentials automatically — instantiate the SDK with no args and it works.\n\n**Use the provider SDK with injected env credentials.** Do not hand-roll a raw `fetch()` against the gateway URL, and do not wire calls to `NETLIFY_AI_GATEWAY_KEY` / `NETLIFY_AI_GATEWAY_URL` as your default path — those are for third-party/unsupported libraries only (see below).\n\n## Footguns (read first)\n\n- **Not browser-callable.** Gateway calls belong in Functions or Edge Functions — never in client-side code. The browser has no injected credentials.\n- **Runtime-only credentials.** Never call the gateway from build scripts, prerender/SSG, or build plugins — those get no credentials and fail. Do AI work at request time; cache to Netlify Blobs if output must look precomputed.\n- **60-second sync timeout.** A gateway call in a synchronous function is bound by the 60s function timeout. Stream long generations (SDK streaming + `ReadableStream`), or use a background function that persists output for the client to fetch. Never leave a slow generation unstreamed.\n- **Requires one production deploy.** The gateway does not activate until a project has at least one production deploy. Even for local dev, run `netlify deploy --prod` once first.\n- **Don't hardcode model lists.** Available models change. Check the live providers endpoint (`https://api.netlify.com/api/v1/ai-gateway/providers/detailed`) rather than baking in a static list.\n- **OpenRouter SDK needs 1.2.43+.** Earlier versions ignore `OPENROUTER_BASE_URL`, call openrouter.ai directly, and fail with `401 Missing Authentication header`.\n\n## Where code goes\n\nWrite normal Function/handler code — there is no AI-specific file type. A function at `netlify/functions/joke.js` exporting `config = { path: \"/api/joke\" }` is served at `/api/joke` under both `netlify dev` and production.\n\n## Provider SDKs (instantiate with no args)\n\nThe gateway injects each provider's own env vars, so the official SDK works with zero config.\n\nAnthropic Claude:\n```js\nimport Anthropic from '@anthropic-ai/sdk';\nconst anthropic = new Anthropic(); // uses ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL\n\nconst message = await anthropic.messages.create({\n model: 'claude-sonnet-4-5-20250929',\n max_tokens: 1024,\n messages: [{ role: 'user', content: 'Hello!' }]\n});\n```\n\nOpenAI:\n```js\nimport OpenAI from 'openai';\nconst openai = new OpenAI(); // uses OPENAI_API_KEY, OPENAI_BASE_URL\n\nconst completion = await openai.chat.completions.create({\n model: 'gpt-5',\n messages: [{ role: 'user', content: 'Hello!' }]\n});\n```\n\nGoogle Gemini:\n```js\nimport { GoogleGenAI } from '@google/genai';\nconst genAI = new GoogleGenAI({}); // uses GEMINI_API_KEY, GOOGLE_GEMINI_BASE_URL\n\nconst result = await genAI.models.generateContent({\n model: 'gemini-2.5-pro',\n contents: 'Hello!'\n});\n```\n\nTypeSafe (Jev) — structured decisions (e.g. routing/classifying form submissions):\n```ts\nimport type { Config, Context } from '@netlify/functions';\nimport { choice, TypeSafeClient } from '@typesafe-ai/sdk';\n\nexport default async (req: Request, context: Context) => {\n const body = await req.json().catch(() => undefined);\n if (body === undefined)\n return Response.json({ error: 'Request body must be valid JSON.' }, { status: 400 });\n\n const client = new TypeSafeClient(); // uses TYPESAFE_API_KEY, TYPESAFE_BASE_URL\n const { answers } = await client.systemOne({\n state: body,\n questions: {\n team: choice('Route this contact form submission', {\n sales: null,\n support: null,\n spam: null,\n }),\n },\n });\n\n return Response.json({ team: answers.team.choice, requestId: context.requestId });\n};\n\nexport const config: Config = { path: '/api/route', method: 'POST' };\n```\n`systemOne` defaults to the `jev-latest` model. Each question is a `choice(prompt, options)` mapping named options to `null`; the result is at `answers.<question>.choice`. POST a JSON body (e.g. `{\"message\":\"Can someone help us upgrade to 200 seats?\"}`) with `Content-Type: application/json`.\n\nOpenRouter (SDK 1.2.43+ required — see footguns):\n```js\nimport { OpenRouter } from '@openrouter/sdk';\nconst openRouter = new OpenRouter(); // uses OPENROUTER_API_KEY, OPENROUTER_BASE_URL\n\nconst result = await openRouter.chat.send({\n chatRequest: {\n model: 'x-ai/grok-4.5',\n messages: [{ role: 'user', content: 'Hello!' }]\n }\n});\n```\n\nModels available through OpenRouter can be called with either the OpenRouter SDK or the OpenAI SDK using OpenRouter model-ID notation (e.g. `deepseek/deepseek-v4-flash-0731`) — just pass the ID as the `model`.\n\nModel IDs above (`gpt-5`, `claude-sonnet-4-5-20250929`, `gemini-2.5-pro`, `x-ai/grok-4.5`, etc.) are examples that change — check the live providers endpoint.\n\n## Env vars — which to use\n\n**Default:** supported provider SDKs consume their injected provider-specific vars automatically. Instantiate the SDK with no args as shown above (`new OpenAI()`, `new Anthropic()`, `new GoogleGenAI({})`, `new TypeSafeClient()`, `new OpenRouter()`) and the corresponding pair is read for you:\n\n- OpenAI: `OPENAI_API_KEY`, `OPENAI_BASE_URL`\n- Anthropic: `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`\n- Google Gemini: `GEMINI_API_KEY`, `GOOGLE_GEMINI_BASE_URL`\n- OpenRouter: `OPENROUTER_API_KEY`, `OPENROUTER_BASE_URL`\n- TypeSafe: `TYPESAFE_API_KEY`, `TYPESAFE_BASE_URL`\n\n**Explicit-config path:** `NETLIFY_AI_GATEWAY_KEY` and `NETLIFY_AI_GATEWAY_URL` are always injected and never collide with user-set provider vars. Use this pair only when a third-party or unsupported library needs explicit key/base-URL configuration — pass them as constructor arguments. It is not the default; supported SDKs should use their provider-specific vars above.\n\n**Precedence:** Netlify never overrides a key or base URL you set at project or team level. If you set your own provider key, the gateway defers to it. For Gemini specifically, injection is skipped if `GOOGLE_API_KEY` or `GOOGLE_VERTEX_BASE_URL` is set (Vertex/Google-API-key setups win).\n\nTo stop all injection, disable AI Features: https://docs.netlify.com/build/build-with-ai/manage-ai-for-your-team/manage-ai-features/#disable-ai-features\n\n## Full example (Vite + React + Function)\n\nDetect gateway availability by checking for an injected var, then call the SDK.\n\nInstall the client first: `npm install openai`. Then create `netlify/functions/joke.js`:\n```js\nimport process from \"process\";\nimport OpenAI from \"openai\";\n\nexport default async () => {\n if (!process.env.OPENAI_BASE_URL)\n return Response.json({ error: \"AI Gateway not active — deploy to prod once on a credit-based plan\" });\n\n try {\n const client = new OpenAI();\n const res = await client.responses.create({\n model: \"gpt-5-mini\",\n input: [{ role: \"user\", content: \"Give me a short dad joke about coffee\" }],\n reasoning: { effort: \"minimal\" },\n });\n return Response.json({\n joke: res.output_text?.trim() || \"Out of jokes\",\n model: res.model,\n tokens: { input: res.usage.input_tokens, output: res.usage.output_tokens },\n });\n } catch (e) {\n return Response.json({ error: `${e}` }, { status: 500 });\n }\n};\n\nexport const config = { path: \"/api/joke\" };\n```\n\n`src/App.jsx` fetches `/api/joke`:\n```jsx\nimport { useState } from \"react\";\n\nexport default function App() {\n const [joke, setJoke] = useState();\n const [loading, setLoading] = useState(false);\n\n const getJoke = async () => {\n setLoading(true);\n try {\n const res = await fetch(\"/api/joke\");\n setJoke(res.ok ? await res.json() : { error: res.status });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <>\n <button onClick={getJoke} disabled={loading}>\n {loading ? \"Thinking...\" : \"Get joke\"}\n </button>\n <pre>{JSON.stringify(joke, null, 2)}</pre>\n </>\n );\n}\n```\n\n## Local development\n\nTwo options — both need at least one prior production deploy:\n\n1. **Netlify CLI:** `netlify dev` gives full gateway support.\n2. **Vite plugin:** access the gateway locally without `netlify dev`. Add `@netlify/vite-plugin` and run your native dev command (`npm run dev`):\n```js\n// vite.config.js\nimport { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\nimport netlify from \"@netlify/vite-plugin\";\n\nexport default defineConfig({ plugins: [react(), netlify()] })\n```\n\nSetup flow:\n```shell\nnpm install -g netlify-cli@latest\nnetlify login\nnpm create vite@latest dad-jokes -- --template react --no-interactive\ncd dad-jokes && npm install\nnetlify init\nnetlify deploy --prod --open # required: activates the gateway\n```\n\n## Billing, limits, constraints\n\n- **Plans:** Credit-based plans only (Free, Personal, Pro). Enterprise: contact your Account Manager. Legacy plans must switch first. Enabled by default unless you disabled AI Features or set your own provider keys.\n- **Cost:** tokens → USD (provider-published rates) → credits. **$1 USD = 180 credits.**\n- **Rate limits** (per minute, per team, across all projects): Free 90, Personal 450, Pro 1,800, Enterprise 9,000 credits.\n- **Context window:** input limited to 200k tokens.\n- **Prompt caching:** Anthropic — only the default 5-min ephemeral cache; OpenAI — per-account `prompt_cache_key` set for you; Gemini — explicit context caching unsupported.\n- **No pass-through headers** (can't enable header-gated experimental features), **no batch inference**, **no OpenAI priority processing**.\n- **OpenRouter ZDR only:** Netlify routes only to providers with a Zero Data Retention policy. A model listed in the OpenRouter directory but with no ZDR-guaranteeing host is not served. Browse ZDR-eligible models: https://openrouter.ai/models?zdr=true\n- **Privacy:** The gateway does not store prompts or model outputs.\n\n**Cost controls:** Set up rate-limiting rules on AI-calling Functions/Edge Functions to prevent visitor abuse and runaway cost: https://docs.netlify.com/manage/security/secure-access-to-sites/rate-limiting/ — and configure auto-recharge or credit packs: https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/configure-auto-recharge/ · https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/buy-credit-packs/\n\nMonitor usage: https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/monitor-usage-for-credit-based-plans\n\n## References\n\n- Overview: https://docs.netlify.com/build/ai-gateway/overview.md\n- Quickstart: https://docs.netlify.com/build/ai-gateway/quickstart-for-ai-gateway.md\n- Examples: https://docs.netlify.com/build/ai-gateway/examples.md — including the AI SEO Image Generator (Gemini image generation): https://github.com/netlify/examples/tree/main/examples/ai-seo-image-generator and a TanStack Start chat app: https://github.com/netlify-templates/tanstack-template\n\n<!-- Gap: exact directly-served model names (Anthropic/OpenAI/Gemini/TypeSafe) are not statically enumerable — rendered at build time from the live providers endpoint. -->\n\n<!-- system: agent-context/ai-gateway/system.md — human-owned, merged by ctx-gen; edit system.md, not this section -->\n# Netlify house rules (ai-gateway)\n\nThese are org conventions, not docs facts — merged into the rendered skill by\nctx-gen and never generated. Owned by the skills maintainer.\n\n1. Use the provider SDK with the injected env credentials — don't hand-roll\n a raw `fetch()` against the gateway, even though raw REST is a supported\n surface. The body must not present raw REST or the\n `NETLIFY_AI_GATEWAY_KEY` / `NETLIFY_AI_GATEWAY_URL` pair as a\n recommended path — but it MUST still document the pair as facts: always\n injected, never collide with user-set provider vars, and the right choice\n when a third-party or unsupported library needs explicit configuration.\n Demote the recommendation; keep the knowledge.\n2. The gateway is not browser-callable: calls belong in functions or edge\n functions, never client-side code.\n3. Model availability changes: don't hardcode model lists; check the live\n providers endpoint.\n4. Gateway credentials are runtime-only: never call the gateway from build\n scripts, prerender/SSG, or build plugins — those calls get no credentials\n and fail. Do AI work at request time and cache the result (e.g. to\n Netlify Blobs) if it must look precomputed.\n5. Gateway calls in a synchronous function are bound by the 60-second\n timeout: stream long generations (SDK streaming + `ReadableStream`), or\n use a background function that persists output for the client to fetch —\n never leave a slow generation unstreamed and assume it finishes.\n6. When asked which env vars to use — even asked explicitly for the gateway\n pair — open with the default before answering the literal question:\n supported provider SDKs consume their injected provider-specific vars\n (`OPENAI_API_KEY`/`OPENAI_BASE_URL`, etc.) using exactly the per-provider\n instantiation the body shows — restate the body's setup, don't invent\n constructor details here. Then give `NETLIFY_AI_GATEWAY_KEY` /\n `NETLIFY_AI_GATEWAY_URL` as the explicit-config path for third-party\n or unsupported libraries. Answering with the gateway pair alone presents\n hand-wiring as the default, which it is not.\n"SKILL.md line diff
--- before +++ after @@ -1,119 +1,269 @@ --- name: netlify-ai-gateway -description: Guide for using Netlify AI Gateway to access AI models. Use when adding AI capabilities or selecting/changing AI models. Must be read before choosing a model. Covers supported providers (OpenAI, Anthropic, Google), SDK setup, environment variables, and the list of available models. +description: Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys. Reach for this when adding an AI feature to a Netlify app — a chatbot, text summarizer, image generator, joke/content generator, form-submission routing or analysis, or any LLM call — or when wiring the OpenAI/Anthropic/Gemini/TypeSafe/OpenRouter SDK into a Netlify Function, choosing which env vars to use, streaming long generations, or debugging why gateway calls fail at build time or return 401. --- # Netlify AI Gateway -> **IMPORTANT:** Only use models listed in the "Available Models" section below. AI Gateway does not support every model a provider offers. Using an unsupported model will cause runtime errors. +Call AI models from Netlify compute using the provider's official SDK. The gateway injects provider credentials automatically — instantiate the SDK with no args and it works. -Netlify AI Gateway provides access to AI models from multiple providers without managing API keys directly. It is available on all Netlify sites. +**Use the provider SDK with injected env credentials.** Do not hand-roll a raw `fetch()` against the gateway URL, and do not wire calls to `NETLIFY_AI_GATEWAY_KEY` / `NETLIFY_AI_GATEWAY_URL` as your default path — those are for third-party/unsupported libraries only (see below). -## How It Works +## Footguns (read first) -The AI Gateway acts as a proxy — you use standard provider SDKs (OpenAI, Anthropic, Google) but point them at Netlify's gateway URL instead of the provider's API. Netlify handles authentication, rate limiting, and monitoring. +- **Not browser-callable.** Gateway calls belong in Functions or Edge Functions — never in client-side code. The browser has no injected credentials. +- **Runtime-only credentials.** Never call the gateway from build scripts, prerender/SSG, or build plugins — those get no credentials and fail. Do AI work at request time; cache to Netlify Blobs if output must look precomputed. +- **60-second sync timeout.** A gateway call in a synchronous function is bound by the 60s function timeout. Stream long generations (SDK streaming + `ReadableStream`), or use a background function that persists output for the client to fetch. Never leave a slow generation unstreamed. +- **Requires one production deploy.** The gateway does not activate until a project has at least one production deploy. Even for local dev, run `netlify deploy --prod` once first. +- **Don't hardcode model lists.** Available models change. Check the live providers endpoint (`https://api.netlify.com/api/v1/ai-gateway/providers/detailed`) rather than baking in a static list. +- **OpenRouter SDK needs 1.2.43+.** Earlier versions ignore `OPENROUTER_BASE_URL`, call openrouter.ai directly, and fail with `401 Missing Authentication header`. -## Setup +## Where code goes -1. Enable AI on your site in the Netlify UI -2. The environment variable `OPENAI_BASE_URL` is set automatically by Netlify -3. Install the provider SDK you want to use +Write normal Function/handler code — there is no AI-specific file type. A function at `netlify/functions/joke.js` exporting `config = { path: "/api/joke" }` is served at `/api/joke` under both `netlify dev` and production. -No provider API keys are needed — Netlify's gateway handles authentication. +## Provider SDKs (instantiate with no args) -## Using OpenAI SDK +The gateway injects each provider's own env vars, so the official SDK works with zero config. -```bash -npm install openai -``` +Anthropic Claude: +```js +import Anthropic from '@anthropic-ai/sdk'; +const anthropic = new Anthropic(); // uses ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL -```typescript -import OpenAI from "openai"; +const message = await anthropic.messages.create({ + model: 'claude-sonnet-4-5-20250929', + max_tokens: 1024, + messages: [{ role: 'user', content: 'Hello!' }] +}); +``` -const openai = new OpenAI(); -// OPENAI_BASE_URL is auto-configured — no API key or base URL needed +OpenAI: +```js +import OpenAI from 'openai'; +const openai = new OpenAI(); // uses OPENAI_API_KEY, OPENAI_BASE_URL const completion = await openai.chat.completions.create({ - model: "gpt-4o-mini", - messages: [{ role: "user", content: "Hello!" }], + model: 'gpt-5', + messages: [{ role: 'user', content: 'Hello!' }] }); ``` -## Using Anthropic SDK - -```bash -npm install @anthropic-ai/sdk +Google Gemini: +```js +import { GoogleGenAI } from '@google/genai'; +const genAI = new GoogleGenAI({}); // uses GEMINI_API_KEY, GOOGLE_GEMINI_BASE_URL + +const result = await genAI.models.generateContent({ + model: 'gemini-2.5-pro', + contents: 'Hello!' +}); ``` -```typescript -import Anthropic from "@anthropic-ai/sdk"; +TypeSafe (Jev) — structured decisions (e.g. routing/classifying form submissions): +```ts +import type { Config, Context } from '@netlify/functions'; +import { choice, TypeSafeClient } from '@typesafe-ai/sdk'; -const client = new Anthropic({ - baseURL: Netlify.env.get("ANTHROPIC_BASE_URL"), -}); +export default async (req: Request, context: Context) => { + const body = await req.json().catch(() => undefined); + if (body === undefined) + return Response.json({ error: 'Request body must be valid JSON.' }, { status: 400 }); + + const client = new TypeSafeClient(); // uses TYPESAFE_API_KEY, TYPESAFE_BASE_URL + const { answers } = await client.systemOne({ + state: body, + questions: { + team: choice('Route this contact form submission', { + sales: null, + support: null, + spam: null, + }), + }, + }); -const message = await client.messages.create({ - model: "claude-sonnet-4-5-20250929", - max_tokens: 1024, - messages: [{ role: "user", content: "Hello!" }], + return Response.json({ team: answers.team.choice, requestId: context.requestId }); +}; + +export const config: Config = { path: '/api/route', method: 'POST' }; +``` +`systemOne` defaults to the `jev-latest` model. Each question is a `choice(prompt, options)` mapping named options to `null`; the result is at `answers.<question>.choice`. POST a JSON body (e.g. `{"message":"Can someone help us upgrade to 200 seats?"}`) with `Content-Type: application/json`. + +OpenRouter (SDK 1.2.43+ required — see footguns): +```js +import { OpenRouter } from '@openrouter/sdk'; +const openRouter = new OpenRouter(); // uses OPENROUTER_API_KEY, OPENROUTER_BASE_URL + +const result = await openRouter.chat.send({ + chatRequest: { + model: 'x-ai/grok-4.5', + messages: [{ role: 'user', content: 'Hello!' }] + } }); ``` -## Using Google AI SDK +Models available through OpenRouter can be called with either the OpenRouter SDK or the OpenAI SDK using OpenRouter model-ID notation (e.g. `deepseek/deepseek-v4-flash-0731`) — just pass the ID as the `model`. -```bash -npm install @google/generative-ai -``` +Model IDs above (`gpt-5`, `claude-sonnet-4-5-20250929`, `gemini-2.5-pro`, `x-ai/grok-4.5`, etc.) are examples that change — check the live providers endpoint. -```typescript -import { GoogleGenerativeAI } from "@google/generative-ai"; +## Env vars — which to use -const genAI = new GoogleGenerativeAI("placeholder"); -// Configure base URL via environment variable +**Default:** supported provider SDKs consume their injected provider-specific vars automatically. Instantiate the SDK with no args as shown above (`new OpenAI()`, `new Anthropic()`, `new GoogleGenAI({})`, `new TypeSafeClient()`, `new OpenRouter()`) and the corresponding pair is read for you: -const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" }); -const result = await model.generateContent("Hello!"); -``` +- OpenAI: `OPENAI_API_KEY`, `OPENAI_BASE_URL` +- Anthropic: `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL` +- Google Gemini: `GEMINI_API_KEY`, `GOOGLE_GEMINI_BASE_URL` +- OpenRouter: `OPENROUTER_API_KEY`, `OPENROUTER_BASE_URL` +- TypeSafe: `TYPESAFE_API_KEY`, `TYPESAFE_BASE_URL` -## In a Netlify Function +**Explicit-config path:** `NETLIFY_AI_GATEWAY_KEY` and `NETLIFY_AI_GATEWAY_URL` are always injected and never collide with user-set provider vars. Use this pair only when a third-party or unsupported library needs explicit key/base-URL configuration — pass them as constructor arguments. It is not the default; supported SDKs should use their provider-specific vars above. -```typescript -import type { Config, Context } from "@netlify/functions"; -import OpenAI from "openai"; +**Precedence:** Netlify never overrides a key or base URL you set at project or team level. If you set your own provider key, the gateway defers to it. For Gemini specifically, injection is skipped if `GOOGLE_API_KEY` or `GOOGLE_VERTEX_BASE_URL` is set (Vertex/Google-API-key setups win). -export default async (req: Request, context: Context) => { - const { prompt } = await req.json(); - const openai = new OpenAI(); +To stop all injection, disable AI Features: https://docs.netlify.com/build/build-with-ai/manage-ai-for-your-team/manage-ai-features/#disable-ai-features - const completion = await openai.chat.completions.create({ - model: "gpt-4o-mini", - messages: [{ role: "user", content: prompt }], - }); +## Full example (Vite + React + Function) - return Response.json({ - response: completion.choices[0].message.content, - }); -}; +Detect gateway availability by checking for an injected var, then call the SDK. -export const config: Config = { - path: "/api/ai", - method: "POST", +Install the client first: `npm install openai`. Then create `netlify/functions/joke.js`: +```js +import process from "process"; +import OpenAI from "openai"; + +export default async () => { + if (!process.env.OPENAI_BASE_URL) + return Response.json({ error: "AI Gateway not active — deploy to prod once on a credit-based plan" }); + + try { + const client = new OpenAI(); + const res = await client.responses.create({ + model: "gpt-5-mini", + input: [{ role: "user", content: "Give me a short dad joke about coffee" }], + reasoning: { effort: "minimal" }, + }); + return Response.json({ + joke: res.output_text?.trim() || "Out of jokes", + model: res.model, + tokens: { input: res.usage.input_tokens, output: res.usage.output_tokens }, + }); + } catch (e) { + return Response.json({ error: `${e}` }, { status: 500 }); + } }; + +export const config = { path: "/api/joke" }; ``` -## Environment Variables +`src/App.jsx` fetches `/api/joke`: +```jsx +import { useState } from "react"; + +export default function App() { + const [joke, setJoke] = useState(); + const [loading, setLoading] = useState(false); + + const getJoke = async () => { + setLoading(true); + try { + const res = await fetch("/api/joke"); + setJoke(res.ok ? await res.json() : { error: res.status }); + } finally { + setLoading(false); + } + }; + + return ( + <> + <button onClick={getJoke} disabled={loading}> + {loading ? "Thinking..." : "Get joke"} + </button> + <pre>{JSON.stringify(joke, null, 2)}</pre> + </> + ); +} +``` -| Variable | Provider | Set by | -|---|---|---| -| `OPENAI_BASE_URL` | OpenAI | Netlify (automatic) | -| `ANTHROPIC_BASE_URL` | Anthropic | Netlify (automatic) | +## Local development -These are configured automatically when AI is enabled on the site. No manual setup required. +Two options — both need at least one prior production deploy: -## Local Development +1. **Netlify CLI:** `netlify dev` gives full gateway support. +2. **Vite plugin:** access the gateway locally without `netlify dev`. Add `@netlify/vite-plugin` and run your native dev command (`npm run dev`): +```js +// vite.config.js +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import netlify from "@netlify/vite-plugin"; -With `@netlify/vite-plugin` or `netlify dev`, gateway environment variables are injected automatically. The AI Gateway is accessible during local development after the site has been deployed at least once. +export default defineConfig({ plugins: [react(), netlify()] }) +``` + +Setup flow: +```shell +npm install -g netlify-cli@latest +netlify login +npm create vite@latest dad-jokes -- --template react --no-interactive +cd dad-jokes && npm install +netlify init +netlify deploy --prod --open # required: activates the gateway +``` -## Available Models +## Billing, limits, constraints -For the list of supported models, see https://docs.netlify.com/build/ai-gateway/overview/. +- **Plans:** Credit-based plans only (Free, Personal, Pro). Enterprise: contact your Account Manager. Legacy plans must switch first. Enabled by default unless you disabled AI Features or set your own provider keys. +- **Cost:** tokens → USD (provider-published rates) → credits. **$1 USD = 180 credits.** +- **Rate limits** (per minute, per team, across all projects): Free 90, Personal 450, Pro 1,800, Enterprise 9,000 credits. +- **Context window:** input limited to 200k tokens. +- **Prompt caching:** Anthropic — only the default 5-min ephemeral cache; OpenAI — per-account `prompt_cache_key` set for you; Gemini — explicit context caching unsupported. +- **No pass-through headers** (can't enable header-gated experimental features), **no batch inference**, **no OpenAI priority processing**. +- **OpenRouter ZDR only:** Netlify routes only to providers with a Zero Data Retention policy. A model listed in the OpenRouter directory but with no ZDR-guaranteeing host is not served. Browse ZDR-eligible models: https://openrouter.ai/models?zdr=true +- **Privacy:** The gateway does not store prompts or model outputs. + +**Cost controls:** Set up rate-limiting rules on AI-calling Functions/Edge Functions to prevent visitor abuse and runaway cost: https://docs.netlify.com/manage/security/secure-access-to-sites/rate-limiting/ — and configure auto-recharge or credit packs: https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/configure-auto-recharge/ · https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/buy-credit-packs/ + +Monitor usage: https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/monitor-usage-for-credit-based-plans + +## References + +- Overview: https://docs.netlify.com/build/ai-gateway/overview.md +- Quickstart: https://docs.netlify.com/build/ai-gateway/quickstart-for-ai-gateway.md +- Examples: https://docs.netlify.com/build/ai-gateway/examples.md — including the AI SEO Image Generator (Gemini image generation): https://github.com/netlify/examples/tree/main/examples/ai-seo-image-generator and a TanStack Start chat app: https://github.com/netlify-templates/tanstack-template + +<!-- Gap: exact directly-served model names (Anthropic/OpenAI/Gemini/TypeSafe) are not statically enumerable — rendered at build time from the live providers endpoint. --> + +<!-- system: agent-context/ai-gateway/system.md — human-owned, merged by ctx-gen; edit system.md, not this section --> +# Netlify house rules (ai-gateway) + +These are org conventions, not docs facts — merged into the rendered skill by +ctx-gen and never generated. Owned by the skills maintainer. + +1. Use the provider SDK with the injected env credentials — don't hand-roll + a raw `fetch()` against the gateway, even though raw REST is a supported + surface. The body must not present raw REST or the + `NETLIFY_AI_GATEWAY_KEY` / `NETLIFY_AI_GATEWAY_URL` pair as a + recommended path — but it MUST still document the pair as facts: always + injected, never collide with user-set provider vars, and the right choice + when a third-party or unsupported library needs explicit configuration. + Demote the recommendation; keep the knowledge. +2. The gateway is not browser-callable: calls belong in functions or edge + functions, never client-side code. +3. Model availability changes: don't hardcode model lists; check the live + providers endpoint. +4. Gateway credentials are runtime-only: never call the gateway from build + scripts, prerender/SSG, or build plugins — those calls get no credentials + and fail. Do AI work at request time and cache the result (e.g. to + Netlify Blobs) if it must look precomputed. +5. Gateway calls in a synchronous function are bound by the 60-second + timeout: stream long generations (SDK streaming + `ReadableStream`), or + use a background function that persists output for the client to fetch — + never leave a slow generation unstreamed and assume it finishes. +6. When asked which env vars to use — even asked explicitly for the gateway + pair — open with the default before answering the literal question: + supported provider SDKs consume their injected provider-specific vars + (`OPENAI_API_KEY`/`OPENAI_BASE_URL`, etc.) using exactly the per-provider + instantiation the body shows — restate the body's setup, don't invent + constructor details here. Then give `NETLIFY_AI_GATEWAY_KEY` / + `NETLIFY_AI_GATEWAY_URL` as the explicit-config path for third-party + or unsupported libraries. Answering with the gateway pair alone presents + hand-wiring as the default, which it is not.
Full snapshot data
{
"description": "Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys. Reach for this when adding an AI feature to a Netlify app — a chatbot, text summarizer, image generator, joke/content generator, form-submission routing or analysis, or any LLM call — or when wiring the OpenAI/Anthropic/Gemini/TypeSafe/OpenRouter SDK into a Netlify Function, choosing which env vars to use, streaming long generations, or debugging why gateway calls fail at build time or return 401.",
"included_files": [],
"name": "netlify-ai-gateway",
"skill_md_contents": "---\nname: netlify-ai-gateway\ndescription: Use Netlify AI Gateway to call OpenAI, Anthropic Claude, Google Gemini, TypeSafe (Jev), or OpenRouter-hosted models (xAI/DeepSeek/Meta/Mistral/Qwen) from Netlify Functions or Edge Functions without managing provider accounts or API keys. Reach for this when adding an AI feature to a Netlify app — a chatbot, text summarizer, image generator, joke/content generator, form-submission routing or analysis, or any LLM call — or when wiring the OpenAI/Anthropic/Gemini/TypeSafe/OpenRouter SDK into a Netlify Function, choosing which env vars to use, streaming long generations, or debugging why gateway calls fail at build time or return 401.\n---\n\n# Netlify AI Gateway\n\nCall AI models from Netlify compute using the provider's official SDK. The gateway injects provider credentials automatically — instantiate the SDK with no args and it works.\n\n**Use the provider SDK with injected env credentials.** Do not hand-roll a raw `fetch()` against the gateway URL, and do not wire calls to `NETLIFY_AI_GATEWAY_KEY` / `NETLIFY_AI_GATEWAY_URL` as your default path — those are for third-party/unsupported libraries only (see below).\n\n## Footguns (read first)\n\n- **Not browser-callable.** Gateway calls belong in Functions or Edge Functions — never in client-side code. The browser has no injected credentials.\n- **Runtime-only credentials.** Never call the gateway from build scripts, prerender/SSG, or build plugins — those get no credentials and fail. Do AI work at request time; cache to Netlify Blobs if output must look precomputed.\n- **60-second sync timeout.** A gateway call in a synchronous function is bound by the 60s function timeout. Stream long generations (SDK streaming + `ReadableStream`), or use a background function that persists output for the client to fetch. Never leave a slow generation unstreamed.\n- **Requires one production deploy.** The gateway does not activate until a project has at least one production deploy. Even for local dev, run `netlify deploy --prod` once first.\n- **Don't hardcode model lists.** Available models change. Check the live providers endpoint (`https://api.netlify.com/api/v1/ai-gateway/providers/detailed`) rather than baking in a static list.\n- **OpenRouter SDK needs 1.2.43+.** Earlier versions ignore `OPENROUTER_BASE_URL`, call openrouter.ai directly, and fail with `401 Missing Authentication header`.\n\n## Where code goes\n\nWrite normal Function/handler code — there is no AI-specific file type. A function at `netlify/functions/joke.js` exporting `config = { path: \"/api/joke\" }` is served at `/api/joke` under both `netlify dev` and production.\n\n## Provider SDKs (instantiate with no args)\n\nThe gateway injects each provider's own env vars, so the official SDK works with zero config.\n\nAnthropic Claude:\n```js\nimport Anthropic from '@anthropic-ai/sdk';\nconst anthropic = new Anthropic(); // uses ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL\n\nconst message = await anthropic.messages.create({\n model: 'claude-sonnet-4-5-20250929',\n max_tokens: 1024,\n messages: [{ role: 'user', content: 'Hello!' }]\n});\n```\n\nOpenAI:\n```js\nimport OpenAI from 'openai';\nconst openai = new OpenAI(); // uses OPENAI_API_KEY, OPENAI_BASE_URL\n\nconst completion = await openai.chat.completions.create({\n model: 'gpt-5',\n messages: [{ role: 'user', content: 'Hello!' }]\n});\n```\n\nGoogle Gemini:\n```js\nimport { GoogleGenAI } from '@google/genai';\nconst genAI = new GoogleGenAI({}); // uses GEMINI_API_KEY, GOOGLE_GEMINI_BASE_URL\n\nconst result = await genAI.models.generateContent({\n model: 'gemini-2.5-pro',\n contents: 'Hello!'\n});\n```\n\nTypeSafe (Jev) — structured decisions (e.g. routing/classifying form submissions):\n```ts\nimport type { Config, Context } from '@netlify/functions';\nimport { choice, TypeSafeClient } from '@typesafe-ai/sdk';\n\nexport default async (req: Request, context: Context) => {\n const body = await req.json().catch(() => undefined);\n if (body === undefined)\n return Response.json({ error: 'Request body must be valid JSON.' }, { status: 400 });\n\n const client = new TypeSafeClient(); // uses TYPESAFE_API_KEY, TYPESAFE_BASE_URL\n const { answers } = await client.systemOne({\n state: body,\n questions: {\n team: choice('Route this contact form submission', {\n sales: null,\n support: null,\n spam: null,\n }),\n },\n });\n\n return Response.json({ team: answers.team.choice, requestId: context.requestId });\n};\n\nexport const config: Config = { path: '/api/route', method: 'POST' };\n```\n`systemOne` defaults to the `jev-latest` model. Each question is a `choice(prompt, options)` mapping named options to `null`; the result is at `answers.<question>.choice`. POST a JSON body (e.g. `{\"message\":\"Can someone help us upgrade to 200 seats?\"}`) with `Content-Type: application/json`.\n\nOpenRouter (SDK 1.2.43+ required — see footguns):\n```js\nimport { OpenRouter } from '@openrouter/sdk';\nconst openRouter = new OpenRouter(); // uses OPENROUTER_API_KEY, OPENROUTER_BASE_URL\n\nconst result = await openRouter.chat.send({\n chatRequest: {\n model: 'x-ai/grok-4.5',\n messages: [{ role: 'user', content: 'Hello!' }]\n }\n});\n```\n\nModels available through OpenRouter can be called with either the OpenRouter SDK or the OpenAI SDK using OpenRouter model-ID notation (e.g. `deepseek/deepseek-v4-flash-0731`) — just pass the ID as the `model`.\n\nModel IDs above (`gpt-5`, `claude-sonnet-4-5-20250929`, `gemini-2.5-pro`, `x-ai/grok-4.5`, etc.) are examples that change — check the live providers endpoint.\n\n## Env vars — which to use\n\n**Default:** supported provider SDKs consume their injected provider-specific vars automatically. Instantiate the SDK with no args as shown above (`new OpenAI()`, `new Anthropic()`, `new GoogleGenAI({})`, `new TypeSafeClient()`, `new OpenRouter()`) and the corresponding pair is read for you:\n\n- OpenAI: `OPENAI_API_KEY`, `OPENAI_BASE_URL`\n- Anthropic: `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`\n- Google Gemini: `GEMINI_API_KEY`, `GOOGLE_GEMINI_BASE_URL`\n- OpenRouter: `OPENROUTER_API_KEY`, `OPENROUTER_BASE_URL`\n- TypeSafe: `TYPESAFE_API_KEY`, `TYPESAFE_BASE_URL`\n\n**Explicit-config path:** `NETLIFY_AI_GATEWAY_KEY` and `NETLIFY_AI_GATEWAY_URL` are always injected and never collide with user-set provider vars. Use this pair only when a third-party or unsupported library needs explicit key/base-URL configuration — pass them as constructor arguments. It is not the default; supported SDKs should use their provider-specific vars above.\n\n**Precedence:** Netlify never overrides a key or base URL you set at project or team level. If you set your own provider key, the gateway defers to it. For Gemini specifically, injection is skipped if `GOOGLE_API_KEY` or `GOOGLE_VERTEX_BASE_URL` is set (Vertex/Google-API-key setups win).\n\nTo stop all injection, disable AI Features: https://docs.netlify.com/build/build-with-ai/manage-ai-for-your-team/manage-ai-features/#disable-ai-features\n\n## Full example (Vite + React + Function)\n\nDetect gateway availability by checking for an injected var, then call the SDK.\n\nInstall the client first: `npm install openai`. Then create `netlify/functions/joke.js`:\n```js\nimport process from \"process\";\nimport OpenAI from \"openai\";\n\nexport default async () => {\n if (!process.env.OPENAI_BASE_URL)\n return Response.json({ error: \"AI Gateway not active — deploy to prod once on a credit-based plan\" });\n\n try {\n const client = new OpenAI();\n const res = await client.responses.create({\n model: \"gpt-5-mini\",\n input: [{ role: \"user\", content: \"Give me a short dad joke about coffee\" }],\n reasoning: { effort: \"minimal\" },\n });\n return Response.json({\n joke: res.output_text?.trim() || \"Out of jokes\",\n model: res.model,\n tokens: { input: res.usage.input_tokens, output: res.usage.output_tokens },\n });\n } catch (e) {\n return Response.json({ error: `${e}` }, { status: 500 });\n }\n};\n\nexport const config = { path: \"/api/joke\" };\n```\n\n`src/App.jsx` fetches `/api/joke`:\n```jsx\nimport { useState } from \"react\";\n\nexport default function App() {\n const [joke, setJoke] = useState();\n const [loading, setLoading] = useState(false);\n\n const getJoke = async () => {\n setLoading(true);\n try {\n const res = await fetch(\"/api/joke\");\n setJoke(res.ok ? await res.json() : { error: res.status });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <>\n <button onClick={getJoke} disabled={loading}>\n {loading ? \"Thinking...\" : \"Get joke\"}\n </button>\n <pre>{JSON.stringify(joke, null, 2)}</pre>\n </>\n );\n}\n```\n\n## Local development\n\nTwo options — both need at least one prior production deploy:\n\n1. **Netlify CLI:** `netlify dev` gives full gateway support.\n2. **Vite plugin:** access the gateway locally without `netlify dev`. Add `@netlify/vite-plugin` and run your native dev command (`npm run dev`):\n```js\n// vite.config.js\nimport { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\nimport netlify from \"@netlify/vite-plugin\";\n\nexport default defineConfig({ plugins: [react(), netlify()] })\n```\n\nSetup flow:\n```shell\nnpm install -g netlify-cli@latest\nnetlify login\nnpm create vite@latest dad-jokes -- --template react --no-interactive\ncd dad-jokes && npm install\nnetlify init\nnetlify deploy --prod --open # required: activates the gateway\n```\n\n## Billing, limits, constraints\n\n- **Plans:** Credit-based plans only (Free, Personal, Pro). Enterprise: contact your Account Manager. Legacy plans must switch first. Enabled by default unless you disabled AI Features or set your own provider keys.\n- **Cost:** tokens → USD (provider-published rates) → credits. **$1 USD = 180 credits.**\n- **Rate limits** (per minute, per team, across all projects): Free 90, Personal 450, Pro 1,800, Enterprise 9,000 credits.\n- **Context window:** input limited to 200k tokens.\n- **Prompt caching:** Anthropic — only the default 5-min ephemeral cache; OpenAI — per-account `prompt_cache_key` set for you; Gemini — explicit context caching unsupported.\n- **No pass-through headers** (can't enable header-gated experimental features), **no batch inference**, **no OpenAI priority processing**.\n- **OpenRouter ZDR only:** Netlify routes only to providers with a Zero Data Retention policy. A model listed in the OpenRouter directory but with no ZDR-guaranteeing host is not served. Browse ZDR-eligible models: https://openrouter.ai/models?zdr=true\n- **Privacy:** The gateway does not store prompts or model outputs.\n\n**Cost controls:** Set up rate-limiting rules on AI-calling Functions/Edge Functions to prevent visitor abuse and runaway cost: https://docs.netlify.com/manage/security/secure-access-to-sites/rate-limiting/ — and configure auto-recharge or credit packs: https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/configure-auto-recharge/ · https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/buy-credit-packs/\n\nMonitor usage: https://docs.netlify.com/manage/accounts-and-billing/billing/billing-for-credit-based-plans/monitor-usage-for-credit-based-plans\n\n## References\n\n- Overview: https://docs.netlify.com/build/ai-gateway/overview.md\n- Quickstart: https://docs.netlify.com/build/ai-gateway/quickstart-for-ai-gateway.md\n- Examples: https://docs.netlify.com/build/ai-gateway/examples.md — including the AI SEO Image Generator (Gemini image generation): https://github.com/netlify/examples/tree/main/examples/ai-seo-image-generator and a TanStack Start chat app: https://github.com/netlify-templates/tanstack-template\n\n<!-- Gap: exact directly-served model names (Anthropic/OpenAI/Gemini/TypeSafe) are not statically enumerable — rendered at build time from the live providers endpoint. -->\n\n<!-- system: agent-context/ai-gateway/system.md — human-owned, merged by ctx-gen; edit system.md, not this section -->\n# Netlify house rules (ai-gateway)\n\nThese are org conventions, not docs facts — merged into the rendered skill by\nctx-gen and never generated. Owned by the skills maintainer.\n\n1. Use the provider SDK with the injected env credentials — don't hand-roll\n a raw `fetch()` against the gateway, even though raw REST is a supported\n surface. The body must not present raw REST or the\n `NETLIFY_AI_GATEWAY_KEY` / `NETLIFY_AI_GATEWAY_URL` pair as a\n recommended path — but it MUST still document the pair as facts: always\n injected, never collide with user-set provider vars, and the right choice\n when a third-party or unsupported library needs explicit configuration.\n Demote the recommendation; keep the knowledge.\n2. The gateway is not browser-callable: calls belong in functions or edge\n functions, never client-side code.\n3. Model availability changes: don't hardcode model lists; check the live\n providers endpoint.\n4. Gateway credentials are runtime-only: never call the gateway from build\n scripts, prerender/SSG, or build plugins — those calls get no credentials\n and fail. Do AI work at request time and cache the result (e.g. to\n Netlify Blobs) if it must look precomputed.\n5. Gateway calls in a synchronous function are bound by the 60-second\n timeout: stream long generations (SDK streaming + `ReadableStream`), or\n use a background function that persists output for the client to fetch —\n never leave a slow generation unstreamed and assume it finishes.\n6. When asked which env vars to use — even asked explicitly for the gateway\n pair — open with the default before answering the literal question:\n supported provider SDKs consume their injected provider-specific vars\n (`OPENAI_API_KEY`/`OPENAI_BASE_URL`, etc.) using exactly the per-provider\n instantiation the body shows — restate the body's setup, don't invent\n constructor details here. Then give `NETLIFY_AI_GATEWAY_KEY` /\n `NETLIFY_AI_GATEWAY_URL` as the explicit-config path for third-party\n or unsupported libraries. Answering with the gateway pair alone presents\n hand-wiring as the default, which it is not.\n"
}SHA-256 of public snapshot: 4f5a51a2c306d18183ed12179d686309594a19299f02e815a95d80a9d172eb48