Documentation

Aperture proxies AI API calls through Singapore for lower latency in Asia-Pacific. It's OpenAI-compatible — just change your base_url.

Quick Start

Replace your provider's base URL with your Aperture endpoint. Everything else stays the same.

Step 1 — Get your API key

Create a free account to receive your sg-... key instantly.

Create free account →
from openai import OpenAI

client = OpenAI(
    api_key="sg-xxxxxxxxxxxxxxxxxxxx",
    base_url="https://aperture-ai.run/proxy/openai/v1"
)

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: 'sg-xxxxxxxxxxxxxxxxxxxx',
  baseURL: 'https://aperture-ai.run/proxy/openai/v1',
});

const response = await client.chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Hello!' }],
});
console.log(response.choices[0].message.content);
curl https://aperture-ai.run/proxy/openai/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sg-xxxxxxxxxxxxxxxxxxxx" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello!"}]}'

Authentication

Pass your Aperture API key as a Bearer token in the Authorization header. Your upstream provider keys are stored securely on our server — never exposed to clients.

Authorization: Bearer sg-xxxxxxxxxxxxxxxxxxxx
ℹ️ Note

If VALID_API_KEYS is empty in the server's .env, authentication is disabled (development mode). Always set API keys in production.

Providers

Aperture currently supports three AI providers. Use the path prefix to route to the correct upstream.

# Endpoint pattern
https://aperture-ai.run/proxy/{provider}/v1/...
Provider name Key models Endpoint prefix
openai GPT-5, GPT-4.5, GPT-4o, o3, o4-mini, DALL·E 3, Whisper /proxy/openai/v1/
anthropic Claude 4 Opus, Claude 4 Sonnet, Claude 3.7 Sonnet, Claude 3.5 Haiku /proxy/anthropic/v1/
gemini Gemini 2.5 Pro, Gemini 2.5 Flash, Gemini 2.0 Flash, Gemini 1.5 Pro /proxy/gemini/v1/
deepseek DeepSeek-V3, DeepSeek-R1, DeepSeek-R1-0528, DeepSeek-Coder-V2 /proxy/deepseek/v1/
xai Grok-3, Grok-3 mini, Grok-2 Vision, Grok-2-1212 /proxy/xai/v1/
aliyun Qwen3-235B, Qwen-Max, Qwen-Plus, Qwen-VL-Max, Qwen-Audio /proxy/aliyun/v1/
groq Llama 4 Scout, Llama 3.3 70B, Mixtral 8x7B, Gemma 2 9B /proxy/groq/v1/
moonshot kimi-k2, moonshot-v1-128k, moonshot-v1-32k, moonshot-v1-8k /proxy/moonshot/v1/
zhipu GLM-4-Plus, GLM-4-Air, GLM-4-Flash, GLM-4V-Flash /proxy/zhipu/v1/
baidu ERNIE-4.5, ERNIE-4.0, ERNIE-3.5, ERNIE Speed /proxy/baidu/v1/
mistral Mistral Large 2, Mistral Nemo, Codestral, Pixtral /proxy/mistral/v1/
together Llama 4 Maverick, Llama 4 Scout, Llama 3.1 405B, FLUX.1 /proxy/together/v1/
perplexity Sonar Pro, Sonar Huge, Sonar (online search) /proxy/perplexity/v1/
minimax MiniMax-Text-01, abab6.5s, abab6.5g /proxy/minimax/v1/
stepfun Step-2, Step-1V, Step-1.5V /proxy/stepfun/v1/
cohere Command R+, Command R, Embed v3, Rerank /proxy/cohere/v1/
lingyiwanwu Yi-Lightning, Yi-Large, Yi-Vision /proxy/lingyiwanwu/v1/

GET /health

Public health check endpoint. No authentication required. Used by load balancers and uptime monitors.

# Request
curl https://aperture-ai.run/health

# Response 200
{
  "status": "ok",
  "region": "Singapore",
  "ts": 1748956800000
}

GET /targets

List all active proxy providers. No authentication required.

# Response 200
{
  "targets": ["openai", "anthropic", "aliyun"]
}

GET /api/stats

Returns live usage statistics. Used by the dashboard. Requires authentication if keys are configured.

# Response 200
{
  "totalRequests": 42891,
  "cacheHitRate": "68.3%",
  "cachedKeys": 1204,
  "redisConnected": true,
  "uptime": "3d 14h 22m",
  "targets": ["openai", "anthropic", "aliyun"],
  "cacheTTL": 300,
  "rateLimitMax": 100,
  "rateLimitWindow": 60000
}

* /proxy/:target/*

Forward any request to the configured upstream. Supports all HTTP methods: GET, POST, PUT, DELETE, PATCH.

StatusMeaning
200Success — upstream response forwarded
401Invalid or missing Aperture API key
404Unknown provider name in path
429Rate limit exceeded — retry after window resets
502Upstream provider unreachable

Response headers include:

X-Cache: HIT # served from Redis cache
X-Cache: MISS # fetched from upstream

Response Caching

GET requests are automatically cached in Redis using a hash of the request path + query. When the same request is made again within the TTL window, the cached response is returned instantly — no upstream API call, no cost.

# .env configuration
CACHE_TTL=300 # seconds. Set 0 to disable caching.

Cache TTL by plan:

PlanCache TTL
Free60 seconds
Pro5 minutes
EnterpriseCustom

Rate Limiting

Distributed rate limiting is handled via Redis using a sliding window. When the limit is exceeded, the server responds with 429 Too Many Requests and a Retry-After header.

# .env configuration
RATE_LIMIT_WINDOW_MS=60000 # 1-minute window
RATE_LIMIT_MAX=100 # max requests per window

Rate limits by plan:

PlanLimit
Free100 req / day
Pro10,000 req / day
EnterpriseUnlimited

Streaming

Streaming responses (Server-Sent Events) are fully supported. Set stream: true in your request body — Aperture forwards the stream transparently. Streamed responses are not cached.

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Tell me a story"}],
    stream=True # streaming — works as-is
)
for chunk in response:
    print(chunk.choices[0].delta.content, end="")

Python examples

Using Anthropic via Aperture:

import anthropic

client = anthropic.Anthropic(
    api_key="sg-xxxxxxxxxxxxxxxxxxxx",
    base_url="https://aperture-ai.run/proxy/anthropic"
)

message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello, Claude!"}]
)

Node.js examples

Using Alibaba DashScope via the OpenAI-compatible endpoint:

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: 'sg-xxxxxxxxxxxxxxxxxxxx',
  baseURL: 'https://aperture-ai.run/proxy/aliyun/v1',
});

const res = await client.chat.completions.create({
  model: 'qwen-max',
  messages: [{ role: 'user', content: '你好!' }],
});

cURL examples

Check your API key and provider status:

# Health check (no auth required)
curl https://aperture-ai.run/health

# List providers
curl https://aperture-ai.run/targets

# Call GPT-4o
curl https://aperture-ai.run/proxy/openai/v1/chat/completions \
  -H "Authorization: Bearer sg-xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hi!"}]}'

Questions? Email [email protected] · View pricing →