Connect Your App to AI Gateway
This guide shows how to connect your AI agent or application to the AI Gateway. You construct the proxy URL for a provider you have already created, authenticate (with the rpk ai CLI for local development or with OIDC client credentials for CI and application code), and send your first request with the SDK of your choice.
| The provider’s Connect tab in Agentic Data Plane generates this configuration for you: a gateway-token step, setup instructions for popular clients, and code examples with the provider’s proxy URL prefilled. Copy from the tab to get started quickly, or follow this page for the full flow. |
After completing this guide, you will be able to:
-
Construct the proxy URL for an LLM provider you have configured
-
Authenticate to AI Gateway with the
rpk aiCLI for local development or with OIDC client credentials for CI and programmatic clients -
Send requests through the proxy URL with the SDK of your choice
Prerequisites
-
A configured LLM provider. If you haven’t created one yet, see Configure an LLM provider.
-
For local development, nothing else. You’ll install
rpk aiin the next section. -
For CI or programmatic clients: Your agent’s service account client ID and a client secret, issued from the agent’s Credentials tab. See Service account authorization. To register an agent and issue credentials, see Set Up a Self-Managed Agent.
-
A development environment with your chosen programming language.
Proxy URL anatomy
Every provider you create in AI Gateway gets its own proxy URL:
<gateway-base>/llm/v1/providers/<provider-name>/<upstream-path>
-
<gateway-base>: The AI Gateway base URL for your Agentic Data Plane environment. Cluster-specific subdomain onclusters.rdpa.co(for example,https://aigw.<cluster-id>.clusters.rdpa.co). Copy the exact value from theProxy URLfield on any provider’s Connection card. -
<provider-name>: The name you gave the provider when you created it, for examplemy-openaiorprod-anthropic. -
<upstream-path>: The upstream API path, relative to the provider’s base URL (for example,chat/completionsfor OpenAI, whose default base URL already ends in/v1, orv1/messagesfor Anthropic).
AI Gateway forwards the request to the upstream provider, attaches the configured credentials, and records the request for observability. Your application never sees the upstream API key.
| The provider detail page generates ready-to-run snippets pre-filled with the correct proxy URL and paths. When in doubt, copy from the Connect tab there. |
Use rpk ai for local development
The rpk ai command is the Redpanda AI CLI. Use it to manage AI Gateway resources (LLM providers, MCP servers, OAuth providers) and call MCP tools from the command line. rpk ai is self-contained: it has its own login and its own Agentic Data Plane environment selection, independent of any rpk cloud session.
-
rpk ai installUpdate later with
rpk ai upgrade; remove withrpk ai uninstall.Upgrading rpkdoes not upgrade the plugin. The plugin is a separate binary that stays at its installed version, even acrossrpkupgrades, until you runrpk ai upgrade. New commands and flags in the reference marked "introduced in ai version X" require the plugin at that version or later. -
Sign in. This runs an OAuth device-authorization flow in your browser, caches credentials in
~/.rpai/credentials(readable only by you), then lists the Agentic Data Plane environments in your organization so you can select one:rpk ai auth login -
Select the Agentic Data Plane environment whose AI Gateway you want to target. The
rpk ai env usecommand accepts an environment name or ID and switches the active environment:rpk ai env list rpk ai env use <environment>Inspect the resolved environment and token state at any time with
rpk ai env showandrpk ai auth status. -
Verify the connection:
rpk ai llm-provider list
If the cached token has expired, rpk ai returns a 401; rerun rpk ai auth login to refresh it.
|
|
|
To target a specific AI Gateway URL for a single invocation (for example, a local gateway, or a staging environment the environments list does not include), pass
This overrides the selected environment’s AI Gateway URL for that one command, and the flag is not bound to an environment variable. For a manual or local gateway you use repeatedly, define it once as an environment instead:
|
Environment variables
The rpk ai command honors the following environment variables:
| Variable | Purpose |
|---|---|
|
Static bearer token for the gateway. |
|
Map to |
Authenticate with OIDC client credentials (CI and programmatic)
For application code, CI runners, server-side processes, and headless agents, use the OAuth 2.0 client_credentials grant directly. This is the canonical authentication path for SDK-style usage. rpk ai is for command-line workflows, not for embedding in application code. AI Gateway issues the token itself. For a self-managed agent, copy the token endpoint from the Token endpoint row on the agent’s Setup tab.
| Parameter | Value |
|---|---|
Token endpoint |
|
Discovery URL |
|
Grant type |
|
The token request takes no audience parameter.
-
cURL
-
Python (authlib)
-
Node.js (openid-client)
AUTH_TOKEN=$(curl -s --request POST \
--url '<gateway-base>/oauth/idp/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data client_id=<client-id> \
--data client_secret=<client-secret> | jq -r .access_token)
Replace <gateway-base> with your AI Gateway base URL, and <client-id> and <client-secret> with your service account credentials.
from authlib.integrations.requests_client import OAuth2Session
token_endpoint = "<gateway-base>/oauth/idp/token"
client = OAuth2Session(
client_id="<client-id>",
client_secret="<client-secret>",
token_endpoint=token_endpoint,
)
token = client.fetch_token(grant_type="client_credentials")
access_token = token["access_token"]
Passing token_endpoint to the OAuth2Session constructor lets authlib handle renewal automatically. For client_credentials grants, it fetches a new token rather than using a refresh token.
import * as client from 'openid-client';
const config = await client.discovery(
new URL('<gateway-base>'),
'<client-id>',
'<client-secret>',
);
const tokens = await client.clientCredentialsGrant(config);
const accessToken = tokens.access_token;
This example uses openid-client version 6. Discovery reads the gateway’s /.well-known/openid-configuration document.
Token lifecycle management
Your client is responsible for refreshing tokens before they expire. OIDC access tokens have a limited TTL set by the identity provider and are not automatically renewed by AI Gateway. Check the expires_in field in the token response for the exact duration.
|
-
Proactively refresh at ~80% of the token’s TTL to avoid failed requests.
-
authlib(Python) handles renewal automatically when you passtoken_endpointtoOAuth2Session. -
For other languages, cache the token and its expiry, then request a new token before the current one expires.
-
For SDK code, refresh OIDC client-credentials tokens through your client library (see the
authlibexample above).
Send requests with your SDK
The examples in this section assume you’ve set:
export PROXY_URL="<your-gateway-base>/llm/v1/providers/<provider-name>"
export AUTH_TOKEN="<oidc-access-token>" # from the client_credentials flow above
-
OpenAI SDK
-
Anthropic SDK
-
Google Gemini SDK
-
AWS Bedrock
-
OpenAI-compatible
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ["PROXY_URL"], # .../llm/v1/providers/my-openai
api_key=os.environ["AUTH_TOKEN"], # OIDC access token
)
response = client.chat.completions.create(
model="gpt-4o", # native OpenAI model ID
messages=[{"role": "user", "content": "Hello from AI Gateway"}],
)
print(response.choices[0].message.content)
The OpenAI SDK appends chat/completions to the proxy URL, and AI Gateway forwards the call to OpenAI’s /v1/chat/completions. Use it with any OpenAI provider and, with a different base_url, with any OpenAI-compatible provider (vLLM, Ollama, LM Studio, Together, Groq, OpenRouter).
import os
from anthropic import Anthropic
client = Anthropic(
base_url=os.environ["PROXY_URL"], # .../llm/v1/providers/my-anthropic
auth_token=os.environ["AUTH_TOKEN"], # OIDC access token
)
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello from AI Gateway"}],
)
print(message.content[0].text)
The Anthropic SDK hits v1/messages on the proxy, which AI Gateway forwards to Anthropic. If the provider has Auth passthrough turned on, the Authorization header carries your own Anthropic credential, which AI Gateway forwards unchanged. Send your gateway token in the X-Redpanda-Cloud-Token header instead. The provider’s Connect tab shows only a curl example for passthrough providers, because the Anthropic SDK uses Authorization for the upstream credential.
import os
from google import genai
from google.genai import types
client = genai.Client(
api_key=os.environ["AUTH_TOKEN"], # the SDK requires a key
http_options=types.HttpOptions(
base_url=f"{os.environ['PROXY_URL']}/v1beta", # .../llm/v1/providers/my-google/v1beta
headers={"X-Redpanda-Cloud-Token": os.environ["AUTH_TOKEN"]},
),
)
response = client.models.generate_content(
model="gemini-2.0-flash",
contents="Hello from AI Gateway",
)
print(response.text)
|
Send your gateway token in the |
Bedrock is different: SigV4 signing is performed server-side by AI Gateway using the credentials on the provider. Your client only needs to call the proxy URL with an OIDC access token.
import os, httpx
# Bedrock 4.6+ Anthropic models require an inference profile (us./eu./global.).
# Replace with the inference profile your provider exposes.
response = httpx.post(
f"{os.environ['PROXY_URL']}/model/us.anthropic.claude-sonnet-4-6/invoke",
headers={"Authorization": f"Bearer {os.environ['AUTH_TOKEN']}"},
json={
"anthropic_version": "bedrock-2023-05-31",
"messages": [{"role": "user", "content": "Hello"}],
"max_tokens": 1024,
},
)
print(response.json())
See Inference profiles and IAM for inference-profile selection guidance.
Bedrock’s Converse API works the same way. Send to /model/{MODEL_ID}/converse with a Converse-shaped body. You can also use the AWS SDK’s bedrockruntime client with its BaseEndpoint set to the proxy URL. AI Gateway re-signs the request server-side with the provider’s credentials, so your client never sees AWS keys. The SDK’s own SigV4 signature uses the Authorization header, so send your gateway token in the X-Redpanda-Cloud-Token header.
|
Use the OpenAI SDK with the proxy URL of the OpenAI-compatible provider and whatever model identifier the upstream exposes. If the provider’s upstream base URL has no version segment, add /v1 to the proxy URL, as the provider’s Connect tab does:
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ["PROXY_URL"], # .../llm/v1/providers/my-vllm
api_key=os.environ["AUTH_TOKEN"],
)
response = client.chat.completions.create(
model="meta-llama/Llama-3.3-70B-Instruct", # as exposed by your upstream
messages=[{"role": "user", "content": "Hello"}],
)
|
The provider detail page also has per-client setup guides, for clients such as Claude Code, Codex, Cline, Roo Code, Cursor, Aider, and OpenCode. Which guides appear depends on the provider type. Open the provider’s Connect tab to see them. |
Group a session’s requests with a conversation ID
Agentic Data Plane assembles an agent’s Transcripts tab from OpenTelemetry spans your app exports itself, not from the gateway calls alone. To populate it, stream instrumented spans to the environment’s OTLP endpoint and put the same identifier on every span in the session as the gen_ai.conversation.id attribute. For a self-managed agent, the Setup tab generates this instrumentation; see Set up a self-managed agent. For the span contract, ingestion limits, and validation checks, see Self-Managed Agent Telemetry Reference. See what your agent did explains how transcripts read this attribute.
Also send the X-Redpanda-Genai-Conversation header on every gateway request in the session, set to the same session or thread ID you put on the spans. The gateway stamps that conversation ID on its own record of each call. The header doesn’t affect authentication or whether requests succeed, and it is not a substitute for instrumenting your app. A transcript is built only from the spans your app exports.
Set it through your SDK’s default-headers mechanism so it rides along with both the LLM call and each MCP tool call:
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ["PROXY_URL"],
api_key=os.environ["AUTH_TOKEN"],
default_headers={"X-Redpanda-Genai-Conversation": session_id},
)
Replace session_id with the session or thread identifier your framework already tracks, and stamp the same value on the session’s MCP tool calls.
Streaming responses
Streaming passes through unchanged. Use the SDK’s native streaming API; the proxy forwards the stream byte-for-byte.
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Write a short poem"}],
stream=True,
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
Handle errors
AI Gateway returns standard HTTP status codes. The upstream provider’s error body passes through, so your existing SDK error handling works:
| Status | Meaning |
|---|---|
400 |
Bad request. Invalid parameters or malformed JSON. |
401 |
Authentication failed. The token is invalid or expired, or wasn’t sent in |
403 |
Forbidden. Nothing grants the service account this action, the provider is disabled, or the requested model isn’t enabled on the provider ( |
404 |
Provider not found. Verify the provider name in the URL. |
429 |
Rate limited. Either the upstream provider is rate limiting you, or the agent’s budget is exhausted. A budget block uses the provider’s own rate-limit error format, and its message names the budget and when it resets. See Set Up Budgets. Respect |
5xx |
Upstream or gateway error. Retry with exponential backoff. |
Best practices
-
Use environment variables for the proxy URL and token. Never hard-code them.
-
Refresh OIDC tokens through your client library so refresh is invisible to your SDK code (
authlibfor Python,openid-clientfor Node.js, and so on). -
Implement retry with exponential backoff for 5xx and timeout conditions.
-
Respect
Retry-Afteron 429 responses. -
Rotate service account credentials on a schedule your organization accepts.
-
Observe usage in Redpanda Agentic Data Plane on each provider’s detail page.
Troubleshooting
These are the most common errors when sending requests through the proxy URL, and how to resolve them.
401 Unauthorized
-
If you’re using
rpk ai: Rerunrpk ai auth loginto refresh the credentials. Token expiry surfaces as a 401. -
If you’re using OAuth client credentials: Check the token hasn’t expired and refresh it. Confirm you requested it from
<gateway-base>/oauth/idp/tokenand that theAuthorizationheader is formattedBearer <token>. -
For Gemini: Ensure the token is sent in the
X-Redpanda-Cloud-Tokenheader. AI Gateway doesn’t readx-goog-api-key. -
For a provider with
Auth passthrough: Ensure the client sends the gateway token inX-Redpanda-Cloud-Tokenand a valid upstream credential inAuthorization.
404 Not Found
-
Re-check the provider name in the proxy URL. The segment after
/providers/must match the provider’s name exactly.
403 Forbidden
-
The service account may lack the required access. Ask an admin for an access policy that names the service account as its principal and grants
Action::"LLMProvider.invoke", plusAction::"LLMProvider.get"if the account also reads provider config. No built-in role short of Admin grants these. See LLM provider permissions. -
The provider may be disabled. Check the badge next to the provider’s name on its detail page.
-
If the response is
model_not_allowed, the requested model isn’t enabled on the provider. Enable it on the provider’s Models tab, or request a model that is enabled.