Govern model calls with the gateway
The Bairav AI Gateway is an OpenAI-compatible proxy. Your application keeps using its normal client; you change the base URL. Every call is then checked against your policies, recorded in the Audit ledger and accounted for tokens and cost.
Your provider key stays yours. Keep sending it in Authorization. The gateway forwards it to the provider and never stores it.
What you need
- A Bairav account with the admin role, to create a gateway key.
- Your own model provider key. Any provider that offers an OpenAI-compatible API works.
- About five minutes.
1. Create a gateway key
In the console open OpenAI gateway and create a key, or call the API:
curl -X POST "https://$BAIRAV_HOST/api/gateway/keys" \
-H "Authorization: Bearer $BAIRAV_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "support-bot"}'
The response contains openai_base_url, for example https://your-tenant.example.com/gw/bst_xxxxxxxx.xxxxxxxx/v1.
Store it now; it cannot be retrieved later. Because the key is in the URL path, treat the whole base URL as a secret: it appears in access logs and shell history. Revoke the key if it leaks (DELETE /api/gateway/keys/{key_id}).
The key records which upstream it forwards to (upstream_base_url, default https://api.openai.com/v1) and how usage is billed (commercial, self_hosted or unknown).
2. Send a call through the gateway
Set two environment variables, then run the sample for your language.
export BAIRAV_GATEWAY_URL="https://your-tenant.example.com/gw/bst_xxxxxxxx.xxxxxxxx/v1"
export OPENAI_API_KEY="your own provider key"
- curl
- Python
- Node.js
#!/usr/bin/env bash
# Send one governed chat completion through the Bairav AI Gateway.
set -euo pipefail
: "${BAIRAV_GATEWAY_URL:?Set BAIRAV_GATEWAY_URL to the openai_base_url of your gateway key, for example https://your-tenant.example.com/gw/bst_xxxxxxxx.xxxxxxxx/v1}"
: "${OPENAI_API_KEY:?Set OPENAI_API_KEY to your own model provider key}"
# -D - prints the response headers so you can see X-Bairav-Blocked when a policy blocks the call.
curl --silent --show-error -D - \
"${BAIRAV_GATEWAY_URL}/chat/completions" \
-H "Authorization: Bearer ${OPENAI_API_KEY}" \
-H "Content-Type: application/json" \
-H "X-Bairav-Agent: support-bot" \
-d '{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Summarise our refund policy in two sentences."}]
}'
"""Send one governed chat completion through the Bairav AI Gateway (openai>=1.0)."""
import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ["BAIRAV_GATEWAY_URL"], # the openai_base_url of your gateway key
api_key=os.environ["OPENAI_API_KEY"], # your own provider key; Bairav forwards it and never stores it
default_headers={"X-Bairav-Agent": "support-bot"}, # the agent name shown in your Registry
)
raw = client.chat.completions.with_raw_response.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Summarise our refund policy in two sentences."}],
)
completion = raw.parse()
answer = completion.choices[0].message.content
# A blocked call comes back as a normal completion with HTTP 200, so check the header.
if raw.headers.get("X-Bairav-Blocked") == "1":
print("Blocked by a Bairav policy:", answer)
else:
print(answer)
// Send one governed chat completion through the Bairav AI Gateway (openai >= 4).
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: process.env.BAIRAV_GATEWAY_URL, // the openai_base_url of your gateway key
apiKey: process.env.OPENAI_API_KEY, // your own provider key; Bairav forwards it and never stores it
defaultHeaders: { 'X-Bairav-Agent': 'support-bot' }, // the agent name shown in your Registry
});
const { data, response } = await client.chat.completions
.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Summarise our refund policy in two sentences.' }],
})
.withResponse();
const answer = data.choices[0].message.content;
// A blocked call comes back as a normal completion with HTTP 200, so check the header.
if (response.headers.get('x-bairav-blocked') === '1') {
console.log('Blocked by a Bairav policy:', answer);
} else {
console.log(answer);
}
The header X-Bairav-Agent names the agent. The first call from a new name registers it, and it appears in the Intake queue for a reviewer to approve.
3. See what Bairav recorded
- The call appears in Gateway and Traffic with its decision, tokens and latency.
- The agent appears in the Intake queue (first call) and then the Registry.
- The decision is written to the Audit ledger.
How a call is decided
- The request shape is checked. A missing
messagesarray returns400. - Kill switch. Agents that are suspended, blocked or rejected are refused.
- Guardrail patterns are matched against the latest user message.
- An optional AI judge can escalate the decision; it never relaxes one and fails safe.
- The request is forwarded to your provider.
- The answer and any tool calls are checked, then your control policies apply:
block,require_approval(the call isgated),flagornotify. - The decision, tokens and latency are recorded.
Handle a blocked call
A refusal is a normal completion with HTTP 200, so existing client code does not throw. As a stream, it arrives as server-sent events. Check the response header:
HTTP/1.1 200 OK
X-Bairav-Blocked: 1
The samples above read this header. Do not treat a 200 as proof the model answered.
Status codes
| Status | Meaning |
|---|---|
200 | A completion from your provider, or a refusal (check X-Bairav-Blocked) |
400 | The request has no messages array |
401 | The gateway key is invalid or revoked: {"error": {"message": "Invalid or revoked Bairav gateway key", "type": "invalid_request_error"}} |
502 | Your provider could not be reached |
The gateway fails open on its own internal errors: if a governance lookup fails, the call degrades to a plain proxy rather than breaking your application.
Headers
| Header | Purpose |
|---|---|
Authorization: Bearer <provider key> | Your own provider key. Forwarded, never stored. |
X-Bairav-Agent | Agent name, at most 128 characters. Default OpenAI Agent. |
X-Bairav-Trace-Id or traceparent | Group several calls into one trace. |
Idempotency-Key | Stops a retried call being counted twice in cost accounting. |
Other provider endpoints
GET and POST under /gw/{token}/v1/ other than chat completions are forwarded unchanged after the key is checked (for example listing models, or embeddings). Only embeddings are accounted for tokens and cost.
Next
- Report tool calls and database actions with the reasoning trail.
- Preview a policy change with Try it out before you publish it.
- Gateway API reference