API Documentation
OpenAI-compatible proxy reference
Overview
AIProxyAPI is an OpenAI-compatible API gateway that proxies requests to Claude and other AI models.
Deploy this service once and call it from any app using the OpenAI SDK or plain HTTP โ no provider key management in your client apps. The proxy handles authentication, rate limiting forwarding, and SSE streaming.
OpenAI-compatible
Drop-in replacement for any app using the OpenAI SDK
SSE Streaming
Real-time token streaming via Server-Sent Events
Key Isolation
Provider keys stay on the server โ never in client code
Base URL
https://your-proxy-domain.comReplace with your deployed domain. All API paths are relative to this base URL.
Quick Start
Get your first response in under 60 seconds.
Step 1 โ Verify the proxy is running
curl https://your-proxy-domain.com/api/healthz
Step 2 โ List available models
curl https://your-proxy-domain.com/v1/models \ -H "Authorization: Bearer MY_PROXY_API_KEY"
Step 3 โ Send a chat completion (streaming)
curl -X POST https://your-proxy-domain.com/v1/chat/completions \
-H "Authorization: Bearer MY_PROXY_API_KEY" -H"Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4.6",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'Using the OpenAI Python SDK
from openai import OpenAI
client = OpenAI(
api_key="MY_PROXY_API_KEY",
base_url="https://your-proxy-domain.com/v1"
)
response = client.chat.completions.create(
model="claude-sonnet-4.6",
messages=[{"role": "user", "content": "Hello!"}],
stream=True
)
for chunk in response:
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)Using the OpenAI Node.js SDK
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.PROXY_API_KEY,
baseURL: 'https://your-proxy-domain.com/v1',
});
const stream = await client.chat.completions.create({
model: 'claude-sonnet-4.6',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content ?? '';
process.stdout.write(content);
}Authentication
All endpoints (except /api/healthz) require a Bearer token.
Authorization Header
Authorization: Bearer MY_PROXY_API_KEY
MY_PROXY_API_KEY is the key you set in your proxy server's PROXY_API_KEY environment variable. This is NOT your provider (Anthropic/Pioneer.ai) API key โ that key lives only on the server.
โ Correct usage
Client apps store only MY_PROXY_API_KEY. Provider keys are set as server environment variables and never sent to clients.
โ Never do this
Never put your Anthropic / Pioneer.ai API key in frontend code, environment variables accessible to the browser, or public repositories.
If a request is made without a valid Bearer token, the proxy returns HTTP 401 Unauthorized with body {"error": "Unauthorized"}.
Endpoints
Three endpoints are exposed. All follow the OpenAI API format.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/models | Required | List available models |
| POST | /v1/chat/completions | Required | Create a chat completion (streaming or full) |
| GET | /api/healthz | None | Health check โ no auth required |
/v1/modelsReturns the list of AI models available through this proxy. Compatible with the OpenAI GET /v1/models format.
curl https://your-proxy-domain.com/v1/models \ -H "Authorization: Bearer MY_PROXY_API_KEY"
Response 200 OK
{
"object": "list",
"data": [
{
"id": "claude-sonnet-4.6",
"object": "model",
"created": 1748700000,
"owned_by": "anthropic"
},
{
"id": "claude-sonnet-4-5",
"object": "model",
"created": 1748700000,
"owned_by": "anthropic"
},
{
"id": "claude-opus-4",
"object": "model",
"created": 1748700000,
"owned_by": "anthropic"
},
{
"id": "claude-haiku-3-5",
"object": "model",
"created": 1748700000,
"owned_by": "anthropic"
}
]
}/v1/chat/completionsCreates a chat completion. Supports both streaming (SSE) and non-streaming modes. The request/response format is identical to the OpenAI Chat Completions API.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| model | string | required | Model ID from GET /v1/modelse.g. claude-sonnet-4.6 |
| messages | array | required | Array of message objects with role and content fields |
| stream | boolean | optional | If true, tokens are streamed via SSE. If false, full response is returned.e.g. true |
| temperature | number | optional | Sampling temperature 0โ2. Higher = more random.e.g. 0.7 |
| max_tokens | integer | optional | Maximum number of tokens to generate.e.g. 512 |
| top_p | number | optional | Nucleus sampling probability threshold.e.g. 0.9 |
| stop | string | array | optional | Stop sequence(s) โ generation stops when encountered. |
Request body example
{
"model": "claude-sonnet-4.6",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain API proxies in one sentence."}
],
"stream": false,
"temperature": 0.7,
"max_tokens": 256
}Response 200 OK (non-streaming)
{
"id": "chatcmpl-abc123xyz",
"object": "chat.completion",
"created": 1748700000,
"model": "claude-sonnet-4.6",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "An API proxy is a server that forwards client requests to a backend service, adding authentication, rate limiting, or transformation along the way."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 32,
"completion_tokens": 38,
"total_tokens": 70
}
}/api/healthzHealth check endpoint. No authentication required. Use this to verify the proxy is running before sending requests. Suitable for load balancer health probes.
curl https://your-proxy-domain.com/api/healthz
{
"status": "ok",
"version": "1.0.0",
"timestamp": "2026-05-31T16:38:12Z"
}Streaming (SSE)
When stream=true, the server sends Server-Sent Events until the response is complete.
Each SSE chunk is a line starting with data: followed by a JSON object. The stream ends with data: [DONE].
curl -X POST https://your-proxy-domain.com/v1/chat/completions \
-H "Authorization: Bearer MY_PROXY_API_KEY" -H"Content-Type: application/json" -H"Accept: text/event-stream" \
-d '{
"model": "claude-sonnet-4.6",
"messages": [{"role": "user", "content": "Count to 5."}],
"stream": true
}'SSE Response format
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1748700000,"model":"claude-sonnet-4.6","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1748700000,"model":"claude-sonnet-4.6","choices":[{"index":0,"delta":{"content":"1"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1748700000,"model":"claude-sonnet-4.6","choices":[{"index":0,"delta":{"content":", 2"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1748700000,"model":"claude-sonnet-4.6","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]Consuming SSE in JavaScript
const response = await fetch('https://your-proxy-domain.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer MY_PROXY_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'claude-sonnet-4.6',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true,
}),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const lines = decoder.decode(value).split('\n');
for (const line of lines) {
if (!line.startsWith('data: ')) continue;
const data = line.slice(6);
if (data === '[DONE]') break;
const chunk = JSON.parse(data);
const content = chunk.choices[0]?.delta?.content ?? '';
process.stdout.write(content);
}
}Response Headers (streaming)
Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive X-Accel-Buffering: no
Error Codes
All error responses use a consistent JSON body format.
{
"error": {
"message": "Invalid API key. Check your Authorization header.",
"type": "authentication_error",
"code": "invalid_api_key"
}
}| Code | Status | Description |
|---|---|---|
| 200 | OK | Request succeeded. Response body contains completion. |
| 400 | Bad Request | Missing required fields or malformed JSON body. |
| 401 | Unauthorized | Missing or invalid Authorization: Bearer header. Check your proxy API key. |
| 404 | Not Found | Unknown model ID. Call GET /v1/models to list available models. |
| 429 | Too Many Requests | Rate limit exceeded on the upstream provider. Retry after the Retry-After header value. |
| 500 | Internal Server Error | Proxy server error or upstream provider failure. Check provider status. |
| 503 | Service Unavailable | Upstream provider API is unreachable. Retry with exponential backoff. |
Environment Variables
Configure these on your server before starting the proxy.
| Variable | Required | Description | Example |
|---|---|---|---|
| PROVIDER_API_KEY | required | Your upstream provider API key (Pioneer.ai, AgentRouter, or Anthropic). Never exposed to clients. | sk-ant-api03-... |
| PROXY_API_KEY | required | The key your clients use to authenticate with this proxy. Set to any strong random string. | sk-proxy-f8a2... |
| PROVIDER_BASE_URL | required | Base URL of the upstream OpenAI-compatible provider. | https://api.pioneer.ai/v1 |
| PORT | optional | Port the proxy server listens on. | 3000 |
| ALLOWED_ORIGINS | optional | Comma-separated list of allowed CORS origins. Use * for public access. | https://myapp.com,https://app2.com |
| REQUEST_BODY_LIMIT | optional | Maximum request body size accepted by the proxy. | 4mb |
| NODE_ENV | optional | Set to production for optimized builds. | production |
.env file template
# Required โ upstream provider credentials PROVIDER_API_KEY=sk-ant-api03-your-key-here PROVIDER_BASE_URL=https://api.pioneer.ai/v1 # Required โ your proxy's own API key (clients use this) PROXY_API_KEY=sk-proxy-generate-a-strong-random-key # Optional PORT=3000 ALLOWED_ORIGINS=* REQUEST_BODY_LIMIT=4mb NODE_ENV=production
Deployment
Build and run the proxy server in production.
Build command
npm run build
Start command
npm run start
Deploy to Railway / Render / Fly.io
Push your repo to GitHub
Connect the repo to Railway / Render / Fly.io
Set PROVIDER_API_KEY, PROXY_API_KEY, PROVIDER_BASE_URL as environment variables in the dashboard
Set build command to npm run build and start command to npm run start
Deploy and verify with: curl https://your-domain.com/api/healthz
Verify deployment โ full test sequence
# 1. Health check (no auth required)
curl https://your-proxy-domain.com/api/healthz
# 2. List models
curl https://your-proxy-domain.com/v1/models \
-H "Authorization: Bearer MY_PROXY_API_KEY"
# 3. Non-streaming completion
curl -X POST https://your-proxy-domain.com/v1/chat/completions \
-H "Authorization: Bearer MY_PROXY_API_KEY" -H"Content-Type: application/json" \
-d '{"model":"claude-sonnet-4.6","messages":[{"role":"user","content":"Say hi."}],"stream":false}'
# 4. Streaming completion
curl -X POST https://your-proxy-domain.com/v1/chat/completions \
-H "Authorization: Bearer MY_PROXY_API_KEY" -H"Content-Type: application/json" \
-d '{"model":"claude-sonnet-4.6","messages":[{"role":"user","content":"Count to 3."}],"stream":true}'CORS Configuration
Set ALLOWED_ORIGINS=* to allow all origins (development), or specify your frontend domain(s) for production: ALLOWED_ORIGINS=https://myapp.com. The proxy sets appropriate Access-Control-Allow-Origin headers automatically.