Private Preview
This feature is in private preview: it's not ready for production use, and it may be briefly unavailable as we deploy updates. To get access, sign up here.
AI Gateway uses Neon bearer credentials, the same credential system as Neon Storage. No provider API keys are needed.
Creating a credential
A credential must include the ai_gateway:invoke scope.
In the Neon Console, select your branch and click Credentials under APP BACKEND in the sidebar. Click Create credential, give it a name, and check ai_gateway:invoke.
After creation, the credential is shown once. Copy the snippet or click Download .env before closing. The snippet includes all four gateway env vars (see Environment variables below).
To view or revoke credentials later, return to the Credentials page and use the action menu (⋮) next to the credential.
Pull credentials with neon
For local development, neon env pull writes your AI Gateway credentials to your .env file automatically, with no manual copy-paste from the API response:
neon env pull .envThis populates NEON_AI_GATEWAY_TOKEN and NEON_AI_GATEWAY_BASE_URL for the current branch alongside your database connection string. Running neon config apply or neon deploy also auto-pulls credentials after a successful apply. To check current credential status:
neon config statusFor production deployments, use the API-based workflow to create named credentials with optional expiry.
Using your credential
Pass your credential as a bearer token on every request:
Authorization: Bearer <your-credential>When using an AI SDK, set this as the apiKey parameter:
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.NEON_AI_GATEWAY_TOKEN,
baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/ai-gateway/mlflow/v1`,
});Environment variables
Neon provides four gateway env vars. Two follow OpenAI's standard naming so existing SDKs pick them up automatically. Two use NEON_-prefixed names that survive a user overriding the OPENAI_* variables with their own provider keys.
| Variable | Value |
|---|---|
OPENAI_API_KEY | Bearer token (nt_live_...) |
OPENAI_BASE_URL | Full OpenAI Responses dialect URL: https://<branch-host>/ai-gateway/openai/v1 — includes the path |
NEON_AI_GATEWAY_TOKEN | Same bearer token as OPENAI_API_KEY |
NEON_AI_GATEWAY_BASE_URL | Bare branch host: https://<branch-host> — no path; append /ai-gateway/<dialect>/v1 yourself |
OPENAI_BASE_URL and NEON_AI_GATEWAY_BASE_URL point at different URLs. OPENAI_BASE_URL already includes /ai-gateway/openai/v1, so new OpenAI() picks it up with zero config and calls the Responses API. NEON_AI_GATEWAY_BASE_URL is the bare host — append the dialect path yourself:
NEON_AI_GATEWAY_BASE_URL + /ai-gateway/mlflow/v1 → chat completions (all providers)
NEON_AI_GATEWAY_BASE_URL + /ai-gateway/openai/v1 → OpenAI Responses API (= OPENAI_BASE_URL)
NEON_AI_GATEWAY_BASE_URL + /ai-gateway/anthropic → Anthropic Messages API
NEON_AI_GATEWAY_BASE_URL + /ai-gateway/gemini → Gemini generateContent APICredentials in Neon Functions
When your code runs inside Neon Functions, all four env vars are injected automatically. No credential creation step required:
| Variable | Value |
|---|---|
NEON_AI_GATEWAY_TOKEN | Bearer token for the AI Gateway |
NEON_AI_GATEWAY_BASE_URL | Branch gateway host with https:// prefix, no path |
OPENAI_API_KEY | Same value as NEON_AI_GATEWAY_TOKEN |
OPENAI_BASE_URL | Branch gateway host including the OpenAI Responses path |
new OpenAI() works with zero configuration because OPENAI_API_KEY and OPENAI_BASE_URL are already set:
import OpenAI from 'openai';
// Reads OPENAI_API_KEY + OPENAI_BASE_URL from the environment automatically.
const client = new OpenAI();
const response = await client.responses.create({
model: 'gpt-5-mini',
input: 'What is Neon?',
});For the chat completions endpoint or when you need credentials that survive a user overriding OPENAI_* with their own keys, use the NEON_AI_GATEWAY_* vars:
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.NEON_AI_GATEWAY_TOKEN,
baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/ai-gateway/mlflow/v1`,
});How branch binding works
Each credential is tied to the branch it was created on. It's valid for:
- That branch (the anchor branch)
- Any branch descended from it: preview branches, feature branches, CI branches
It's not valid for branches outside that lineage.
This means a credential created on your main branch works in all branches that were forked from main. A credential created on a feature branch only works within that feature branch's descendants.
main ──── credential valid here
└── preview/feature-x ──── and here
└── preview/sub-branch ──── and here
staging ──── credential NOT valid here (different lineage)This design lets you use a single credential across your entire development workflow (local dev, preview deployments, and CI) without creating separate credentials for each environment.
Common auth errors
| Error | Cause | Fix |
|---|---|---|
401 Unauthorized | Missing or invalid credential | Check that NEON_AI_GATEWAY_TOKEN is set and contains the full token |
403 Forbidden | Credential lacks ai_gateway:invoke scope | Recreate the credential with the correct scope |
403 Forbidden | Branch not in credential lineage | Use a credential created on this branch or an ancestor branch. The gateway returns: credential not authorized for this branch |
503 Service Unavailable | Auth store temporarily unavailable | Retry the request |
Rotating credentials
To rotate a credential: create a new one, update your environment variables, then revoke the old one.
To revoke from the Console, open the Credentials page and use the action menu (⋮) next to the credential. To revoke via the API:
curl -X DELETE "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/credentials/{token_id}" \
-H "Authorization: Bearer $NEON_API_KEY"Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.








