Base URL
http://localhost:8080/v1
The Gateway exposes an OpenAI-compatible API. Any client or SDK that works with OpenAI works with Anar Gateway by pointing the base URL to the Gateway.
OpenAI-Compatible Endpoints
Health Check
/healthReturns the Gateway health status
curl http://localhost:8080/health
Returns 200 OK when the Gateway is ready to accept requests.
Chat Completions
/v1/chat/completionsCreate a chat completion with optional streaming
Supports all OpenAI chat completion parameters including streaming via Server-Sent Events.
Request:
{
"model": "llama-3.3-70b-versatile",
"messages": [
{"role": "system", "content": "You are a helpful government AI assistant."},
{"role": "user", "content": "What is the UAE's national AI strategy?"}
],
"temperature": 0.7,
"max_tokens": 1024,
"stream": false
}
Response:
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"model": "llama-3.3-70b-versatile",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The UAE National Strategy for Artificial Intelligence 2031..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 28,
"completion_tokens": 150,
"total_tokens": 178
}
}
Streaming:
Set "stream": true to receive Server-Sent Events:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3.3-70b-versatile",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'
Each SSE chunk follows the OpenAI streaming format:
data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"Hello"},"index":0}]}
data: {"id":"chatcmpl-abc","choices":[{"delta":{},"finish_reason":"stop","index":0}]}
data: [DONE]
Embeddings
/v1/embeddingsGenerate text embeddings
Request:
{
"model": "text-embedding-3-large-uaenorth",
"input": "Sovereign AI infrastructure for government"
}
Response:
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [0.0023, -0.0092, 0.0151, ...]
}
],
"model": "text-embedding-3-large-uaenorth",
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
}
The text-embedding-3-large-uaenorth model produces 3072-dimensional vectors deployed in the UAE North sovereign region.
List Models
/v1/modelsList all available models across configured providers
curl http://localhost:8080/v1/models
Returns models from all configured providers with metadata about capabilities and availability.
Management Endpoints
Cost Tracking
/costsQuery usage records with filtering and pagination
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
model | string | Filter by model name |
provider | string | Filter by provider |
tenant_id | string | Filter by tenant/virtual key |
start_time | string | Start of time range (RFC3339) |
end_time | string | End of time range (RFC3339) |
page | int | Page number (default: 1) |
limit | int | Page size (default: 50) |
sort_by | string | Sort field |
sort_dir | string | asc or desc |
Response:
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"request_id": "req-abc123",
"model": "llama-3.3-70b-versatile",
"provider": "groq",
"prompt_tokens": 150,
"completion_tokens": 500,
"total_tokens": 650,
"cost_usd": 0.000484,
"tenant_id": "ministry-dev-key",
"timestamp": "2026-02-16T10:30:00Z"
}
],
"total": 1542,
"page": 1,
"limit": 50
}
/costs/summaryAggregated cost summary by model, provider, tenant, and day
Response:
{
"total_requests": 15420,
"total_cost_usd": 12.847,
"total_tokens": 4521000,
"by_model": [
{
"model": "llama-3.3-70b-versatile",
"requests": 12000,
"prompt_tokens": 1800000,
"completion_tokens": 2400000,
"total_tokens": 4200000,
"cost_usd": 9.96
}
],
"by_provider": [
{"provider": "groq", "requests": 14000, "cost_usd": 10.50},
{"provider": "azure", "requests": 1420, "cost_usd": 2.35}
],
"by_tenant": [
{"tenant_id": "ministry-dev", "requests": 8000, "cost_usd": 5.20}
],
"daily_costs": [
{"date": "2026-02-16", "cost_usd": 1.23}
]
}
/costs/exportExport usage records as CSV download
Returns a CSV file with headers: id, request_id, model, provider, prompt_tokens, completion_tokens, total_tokens, cost_usd, tenant_id, timestamp.
Audit Logs
/logs/eventsSearch audit events with filtering
Query parameters match the same pattern as cost tracking: actor, action, outcome, resource, provider, model, request_id, start_time, end_time, search, page, limit.
/logs/statsAudit event statistics and aggregations
Returns counts by action, outcome, provider, hourly event rates, unique actor counts, and recent failure counts.
Error Responses
All errors follow the OpenAI error format:
{
"error": {
"message": "Descriptive error message",
"type": "error_type"
}
}
Error Types
| Type | Status | Description |
|---|---|---|
rbac_denied | 401/403 | Authentication required or insufficient permissions |
oidc_auth_error | 401 | Invalid or expired OIDC token |
guardrails_blocked | 403 | Content blocked by safety policy |
guardrails_error | 502 | Guard service unavailable (when fail_open: false) |
rate_limit_exceeded | 429 | Budget or rate limit exceeded |
provider_error | 502 | Upstream provider returned an error |
SDK Examples
Python (OpenAI SDK)
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8080/v1",
api_key="sk-anar-dev-key",
)
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Summarize Abu Dhabi's AI investments"},
],
temperature=0.7,
)
print(response.choices[0].message.content)
Streaming:
stream = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
Embeddings:
response = client.embeddings.create(
model="text-embedding-3-large-uaenorth",
input="Sovereign AI for government",
)
vector = response.data[0].embedding # 3072-dimensional
JavaScript (OpenAI SDK)
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "http://localhost:8080/v1",
apiKey: "sk-anar-dev-key",
});
const response = await client.chat.completions.create({
model: "llama-3.3-70b-versatile",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Summarize Abu Dhabi's AI investments" },
],
});
console.log(response.choices[0].message.content);
Streaming:
const stream = await client.chat.completions.create({
model: "llama-3.3-70b-versatile",
messages: [{ role: "user", content: "Hello" }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) process.stdout.write(content);
}
cURL
# Chat completion
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-anar-dev-key" \
-d '{
"model": "llama-3.3-70b-versatile",
"messages": [{"role": "user", "content": "Hello from Anar Gateway"}]
}'
# Embeddings
curl http://localhost:8080/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-anar-dev-key" \
-d '{
"model": "text-embedding-3-large-uaenorth",
"input": "Sovereign AI for government"
}'
# Cost summary
curl "http://localhost:8080/costs/summary?start_time=2026-02-01T00:00:00Z"
# Audit events
curl "http://localhost:8080/logs/events?action=model_request&limit=10"
Authentication
When RBAC or OIDC is enabled, include the Authorization header with all requests:
Authorization: Bearer sk-anar-your-api-key
Or with a JWT token:
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Requests to bypass paths (/health, /metrics) do not require authentication.
Rate Limits
Rate limits are enforced per virtual key, team, or customer scope. When a limit is exceeded, the Gateway returns:
HTTP/1.1 429 Too Many Requests
Retry-After: 30
{
"error": {
"message": "Rate limit exceeded: 100 requests per minute",
"type": "rate_limit_exceeded"
}
}
Rate limits are configurable via the governance API with two dimensions: requests per minute and tokens per minute.