API Documentation

OpenAI-compatible proxy reference

v1.0OpenAI-compatibleOpenAI 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.com

Replace 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

bashโ€” Health check
curl https://your-proxy-domain.com/api/healthz

Step 2 โ€” List available models

bashโ€” GET /v1/models
curl https://your-proxy-domain.com/v1/models \
  -H "Authorization: Bearer MY_PROXY_API_KEY"

Step 3 โ€” Send a chat completion (streaming)

bashโ€” POST /v1/chat/completions (stream)
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

pythonโ€” 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

typescriptโ€” Node.js / TypeScript
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

httpโ€” Header format
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.

MethodPathAuthDescription
GET/v1/modelsRequiredList available models
POST/v1/chat/completionsRequiredCreate a chat completion (streaming or full)
GET/api/healthzNoneHealth check โ€” no auth required
GET/v1/models

Returns the list of AI models available through this proxy. Compatible with the OpenAI GET /v1/models format.

bashโ€” Request
curl https://your-proxy-domain.com/v1/models \
  -H "Authorization: Bearer MY_PROXY_API_KEY"

Response 200 OK

jsonโ€” Response body
{
  "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"
    }
  ]
}
POST/v1/chat/completions

Creates 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

ParameterTypeRequiredDescription
modelstringrequiredModel ID from GET /v1/modelse.g. claude-sonnet-4.6
messagesarrayrequiredArray of message objects with role and content fields
streambooleanoptionalIf true, tokens are streamed via SSE. If false, full response is returned.e.g. true
temperaturenumberoptionalSampling temperature 0โ€“2. Higher = more random.e.g. 0.7
max_tokensintegeroptionalMaximum number of tokens to generate.e.g. 512
top_pnumberoptionalNucleus sampling probability threshold.e.g. 0.9
stopstring | arrayoptionalStop sequence(s) โ€” generation stops when encountered.

Request body example

jsonโ€” Non-streaming request
{
  "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)

jsonโ€” Full response object
{
  "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
  }
}
GET/api/healthz

Health check endpoint. No authentication required. Use this to verify the proxy is running before sending requests. Suitable for load balancer health probes.

bashโ€” Request
curl https://your-proxy-domain.com/api/healthz
jsonโ€” Response 200 OK
{
  "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].

bashโ€” Streaming request
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

textโ€” Raw SSE stream
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

typescriptโ€” fetch + ReadableStream
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)

httpโ€” Server response headers
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.

jsonโ€” Error response body
{
  "error": {
    "message": "Invalid API key. Check your Authorization header.",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}
CodeStatusDescription
200OKRequest succeeded. Response body contains completion.
400Bad RequestMissing required fields or malformed JSON body.
401UnauthorizedMissing or invalid Authorization: Bearer header. Check your proxy API key.
404Not FoundUnknown model ID. Call GET /v1/models to list available models.
429Too Many RequestsRate limit exceeded on the upstream provider. Retry after the Retry-After header value.
500Internal Server ErrorProxy server error or upstream provider failure. Check provider status.
503Service UnavailableUpstream provider API is unreachable. Retry with exponential backoff.

Environment Variables

Configure these on your server before starting the proxy.

VariableRequiredDescriptionExample
PROVIDER_API_KEYrequiredYour upstream provider API key (Pioneer.ai, AgentRouter, or Anthropic). Never exposed to clients.sk-ant-api03-...
PROXY_API_KEYrequiredThe key your clients use to authenticate with this proxy. Set to any strong random string.sk-proxy-f8a2...
PROVIDER_BASE_URLrequiredBase URL of the upstream OpenAI-compatible provider.https://api.pioneer.ai/v1
PORToptionalPort the proxy server listens on.3000
ALLOWED_ORIGINSoptionalComma-separated list of allowed CORS origins. Use * for public access.https://myapp.com,https://app2.com
REQUEST_BODY_LIMIToptionalMaximum request body size accepted by the proxy.4mb
NODE_ENVoptionalSet to production for optimized builds.production

.env file template

bashโ€” .env
# 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

bashโ€” Build
npm run build

Start command

bashโ€” Start
npm run start

Deploy to Railway / Render / Fly.io

1

Push your repo to GitHub

2

Connect the repo to Railway / Render / Fly.io

3

Set PROVIDER_API_KEY, PROXY_API_KEY, PROVIDER_BASE_URL as environment variables in the dashboard

4

Set build command to npm run build and start command to npm run start

5

Deploy and verify with: curl https://your-domain.com/api/healthz

Verify deployment โ€” full test sequence

bashโ€” Deployment verification
# 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.