Proxy API
OpenAI-compatible HTTP API for chat, embeddings, models, memory, sessions, and billing. Route requests through your Arcana license or use your own provider keys directly.
Base URL
https://proxy.arcana.otnelhq.com
All endpoints are under /v1/. The proxy is OpenAI-compatible — drop-in replacements work with any OpenAI SDK or HTTP client.
Authentication
Every request (except public endpoints) requires a license key as a Bearer token:
Authorization: Bearer <license_key>
License keys look like ARCANA-PRO-… and come from arcana console login. Do not send vendor API keys (sk-…) as the proxy bearer.
export ARCANA_LICENSE='ARCANA-PRO-…'
# Quick test
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/health
Anyone with access to your Arcana data directory can use your proxy quota. Never commit credentials; use arcana console logout on shared machines.
POST /v1/chat/completions
OpenAI Chat Completions compatible. Supports streaming SSE, tool calls, and all standard parameters.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model ID (e.g. anthropic/claude-sonnet-4, openai/gpt-4o) |
messages | array | Yes | Array of message objects with role and content |
stream | boolean | No | Enable streaming SSE (default: false) |
temperature | number | No | Sampling temperature (0–2) |
max_tokens | number | No | Maximum tokens to generate |
tools | array | No | Tool definitions for function calling |
curl example
curl -N -X POST https://proxy.arcana.otnelhq.com/v1/chat/completions \
-H "Authorization: Bearer $ARCANA_LICENSE" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "What is Arcana?" }
],
"stream": true
}'
JavaScript example
const response = await fetch("https://proxy.arcana.otnelhq.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.ARCANA_LICENSE}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "anthropic/claude-sonnet-4",
messages: [{ role: "user", content: "Hello!" }],
stream: true,
}),
});
// Stream the response
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
console.log(chunk);
}
Python example
import os, requests
resp = requests.post(
"https://proxy.arcana.otnelhq.com/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['ARCANA_LICENSE']}"},
json={
"model": "anthropic/claude-sonnet-4",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": True,
},
stream=True,
)
for line in resp.iter_lines():
if line:
print(line.decode())
POST /v1/embeddings
OpenAI-compatible embeddings endpoint. Returns vector representations of input text.
curl -X POST https://proxy.arcana.otnelhq.com/v1/embeddings \
-H "Authorization: Bearer $ARCANA_LICENSE" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/text-embedding-3-small",
"input": "The quick brown fox"
}'
{
"object": "list",
"data": [
{
"object": "embedding",
"embedding": [0.0023, -0.0091, 0.0156, ...],
"index": 0
}
],
"model": "openai/text-embedding-3-small",
"usage": { "prompt_tokens": 8, "total_tokens": 8 }
}
GET /v1/models
List all models available through your license. Returns an OpenAI-compatible model list.
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/models
{
"object": "list",
"data": [
{ "id": "openai/gpt-4o", "object": "model", "owned_by": "openai" },
{ "id": "anthropic/claude-sonnet-4", "object": "model", "owned_by": "anthropic" },
{ "id": "google/gemini-2.5-pro", "object": "model", "owned_by": "google" }
]
}
GET /v1/health
Returns identity and liveness information for the authenticated user.
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/health
{
"status": "ok",
"service": "arcana-proxy",
"user": "[email protected]",
"tier": "pro"
}
GET /v1/balance
Returns your current credit balance. Credits are integer units where 100 credits = $1.00.
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/balance
{
"userId": "[email protected]",
"credits": 842,
"dollars": "8.42"
}
GET /v1/usage
Daily request counters for the authenticated subject. Shows token usage and costs per day.
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/usage
GET /v1/free-usage/sessions/current
Free-tier session snapshot showing turns used, weekly tokens, and remaining quota. Only relevant when on the free plan.
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/free-usage/sessions/current
GET /v1/sessions
List recent proxy-recorded sessions with model, tokens, cost, and optional message preview. These are proxy usage records, not full local TUI transcripts.
# List sessions
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/sessions
# Get session detail
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/sessions/ses_abc123
GET / PUT / DELETE /v1/memory
Personal cloud memory facts for the workspace Memory page and arcana memory push|pull|sync. Facts are key-value pairs with confidence scores.
List facts
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/memory
{
"facts": [
{ "key": "user.theme", "value": "dark", "confidence": 1, "updatedAt": "2026-07-20T10:00:00Z" },
{ "key": "project.runtime", "value": "bun", "confidence": 0.9, "updatedAt": "2026-07-19T14:30:00Z" }
]
}
Upsert facts
Upserts use last-write-wins semantics by updatedAt timestamp.
curl -X PUT -H "Authorization: Bearer $ARCANA_LICENSE" \
-H "Content-Type: application/json" \
-d '{
"facts": [
{ "key": "user.theme", "value": "dark", "confidence": 1 },
{ "key": "deploy.target", "value": "cloudflare-workers", "confidence": 0.8 }
]
}' \
https://proxy.arcana.otnelhq.com/v1/memory
Delete a fact
curl -X DELETE -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/memory/user.theme
GET / PUT /v1/profile
User profile preferences used by the workspace UI.
# Get profile
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/profile
# Update profile
curl -X PUT -H "Authorization: Bearer $ARCANA_LICENSE" \
-H "Content-Type: application/json" \
-d '{"displayName": "Alice", "preferences": {"theme": "dark"}}' \
https://proxy.arcana.otnelhq.com/v1/profile
GET /v1/purchases
Purchase history for the authenticated account.
curl -H "Authorization: Bearer $ARCANA_LICENSE" \
https://proxy.arcana.otnelhq.com/v1/purchases
Public endpoints
These endpoints do not require authentication:
GET /v1/identity/validate-email
Check if an email address has an associated Arcana account.
curl "https://proxy.arcana.otnelhq.com/v1/identity/[email protected]"
POST /v1/trial/start
Start a trial token (if enabled for your account).
curl -X POST -H "Content-Type: application/json" \
-d '{"email": "[email protected]"}' \
https://proxy.arcana.otnelhq.com/v1/trial/start
Error handling
The proxy returns standard HTTP status codes and OpenAI-compatible error objects:
{
"error": {
"message": "Invalid license key",
"type": "invalid_request_error",
"code": "invalid_license"
}
}
| HTTP | Meaning | What to do |
|---|---|---|
200 | Success | — |
400 | Bad request | Check request body and parameters |
401 | Unauthorized | Check your license key |
403 | Forbidden | License may be expired or tier too low |
429 | Rate limited | Wait and retry; check Retry-After header |
500 | Server error | Retry or check status page |
Using with SDKs
The proxy is OpenAI-compatible, so any OpenAI SDK works as a drop-in:
OpenAI Node.js SDK
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.ARCANA_LICENSE,
baseURL: "https://proxy.arcana.otnelhq.com/v1",
});
const res = await client.chat.completions.create({
model: "anthropic/claude-sonnet-4",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(res.choices[0].message.content);
OpenAI Python SDK
from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ["ARCANA_LICENSE"],
base_url="https://proxy.arcana.otnelhq.com/v1",
)
res = client.chat.completions.create(
model="anthropic/claude-sonnet-4",
messages=[{"role": "user", "content": "Hello!"}],
)
print(res.choices[0].message.content)
Rate limits
Rate limits depend on your license tier:
| Tier | Requests/min | Tokens/day | Notes |
|---|---|---|---|
| Free | 10 | Limited | Weekly token cap |
| Pro | 60 | Unlimited | Per-provider limits may apply |
| Enterprise | Custom | Unlimited | Contact sales |
When rate limited, the response includes a Retry-After header with the number of seconds to wait.
Proxy vs BYOK
| Feature | Proxy (license) | BYOK (your keys) |
|---|---|---|
| Billing | Arcana credits | Direct to provider |
| Memory sync | Yes (cloud) | Local only |
| Session tracking | Yes (workspace) | Local only |
| Cost ledger | Yes | No |
| Model catalog | All licensed models | Provider-specific |
| Offline use | No | Yes (with local models) |