Get

AI gateway

Use the AI accounts connected to your own AirCode Ø instance from your personal applications. Supply your instance’s Base URL, a separate application token, and an exact model ID. The instance invokes its connected provider CLI and returns the answer through a text-only Chat Completions API.

Your application's backend
  → your instance URL + application token
    → a connected native provider account
      → validated answer + available usage counters

The website hosts documentation only. API requests go directly to your instance; aircodezero.com does not receive your instance address, token or prompts. Use this service only for your own applications and accounts. Provider terms, subscription access and quotas still apply.

Set up the instance

  1. Connect a compatible native provider account in AI Usage. The gateway lists the account models supported by the installed instance; API-key and managed-credit connections are excluded.
  2. Open Settings → AI gateway on desktop/web, or More → AI gateway on native mobile, then turn on Enable AI gateway.
  3. Copy the displayed Base URL. It ends in /api/ai-gateway/v1.
  4. In Application tokens, enter your application’s name, select Create token, and save the token before dismissing its one-time reveal.
  5. Configure these server-side environment variables in your application:
Variable Value
AIRCODE_AI_BASE_URL The full Base URL copied from the instance, without an extra /v1
AIRCODE_AI_TOKEN The application token you just created
AIRCODE_AI_MODEL An exact id from Compatible models or GET /models

Keep tokens in your backend’s secret configuration, not in browser code, a mobile app bundle, a repository, a URL or a shared conversation. The examples read environment variables instead of embedding credentials. Never use the instance password or an owner login token in the API-key field.

The instance must remain running and reachable from your application’s backend. localhost means the computer running that backend. Use the instance’s HTTPS address for remote access, or your trusted local/private-network connection. The gateway does not create a public origin. A provider not listed by /models cannot be selected by inventing an ID.

Authentication and model discovery

Send Authorization: Bearer YOUR_APPLICATION_TOKEN on each call. Send JSON with Content-Type: application/json. No query parameters or cookie authentication are supported. Cross-origin browser calls are not supported; use your backend.

GET {BASE_URL}/models returns an object with object: "list" and a data array. Each model provides an id, display label, engine, engineLabel, provider, connectionLabel and efforts. Pass the returned id unchanged; it may already contain percent encoding. The list can change when accounts, provider access or installed models change.

For an OpenAI-compatible application’s configuration, select Chat Completions, use the full Base URL, put the application token in its API key field, and copy one of the returned model IDs. An application that requires Responses, tools, images or unsupported sampling parameters is not compatible with the current gateway.

Generate a response

POST {BASE_URL}/chat/completions accepts the following fields. Unknown fields are refused rather than silently ignored.

Field Supported value
model Required exact model ID returned by /models
messages Required array of 1–100 messages; at least one non-empty user message
messages[].role system, developer, user or assistant
messages[].content A string, or an array of { "type": "text", "text": "..." } blocks
reasoning_effort Optional value from the selected model’s efforts; omit it for the default
stream Optional boolean; defaults to false
stream_options Only { "include_usage": true } or false for that flag, with stream: true
n Omit it or use 1
store Omit it or use false

Messages contain only role and content. Text blocks are joined with newlines. Null characters are refused. The normalized message array must fit within 64 KiB of UTF-8 JSON; the full HTTP body is limited to 80 KiB. The validated answer is limited to 49,152 JavaScript string code units. These are gateway limits, not promises about a provider’s context window or output capacity.

Supply the complete relevant conversation on every call. To continue a conversation, append the previous assistant answer and the next user message. The gateway does not create or retain a conversation, session or completion history. A token grants no access to instance projects, files, terminal, sessions or owner settings.

A normal response has object: "chat.completion"; read the text from choices[0].message.content. It also includes id, created, the requested model, and finish_reason: "stop". Native counters appear in usage when complete enough to report. The aircode_usage extension preserves accounting details and incomplete estimates. Missing counters or prices are unknown, never zero. API-equivalent estimates are not extra subscription charges.

Streaming

Set stream: true to receive Content-Type: text/event-stream. The current implementation uses buffered streaming: it sends an initial waiting comment and keepalive comments while the provider runs, then sends the complete answer after validation. It does not stream words or tokens as they are generated.

A successful stream contains:

  1. SSE comments beginning with : while waiting; ignore them.
  2. A data: JSON chat.completion.chunk with the assistant role and complete text in choices[0].delta.content.
  3. A chunk with an empty delta and finish_reason: "stop".
  4. An optional chunk with choices: [], usage (possibly null) and aircode_usage when stream_options.include_usage is true.
  5. data: [DONE].

After a stream starts, failures arrive as an SSE data: event containing error; do not treat HTTP 200 alone as success. A failed stream closes without the success marker. SSE frames may be split across transport chunks; use an SDK or an SSE parser rather than parsing each network chunk as JSON.

Closing a connection cancels its active request. Revoking a token, disabling the gateway or stopping the instance also cancels matching work. There is no automatic replay or resume. Long-running requests need an appropriate client and reverse-proxy timeout; keepalives cannot override a network’s absolute request-duration limit.

Quotas, token lifecycle and errors

The gateway allows two active calls instance-wide, one active call per token, and 30 admitted generation requests per token per minute. Calls are not queued. These local limits do not replace provider quotas. Tokens expire after 90 days; create a replacement, update your application, then revoke the previous token. Disabling the gateway retains tokens but suspends their use. Restoring instance state disables the gateway and clears token authority; create fresh tokens.

Errors use error.message, error.type, error.code and error.param. Read the code as well as the HTTP status. Do not automatically retry a generation whose outcome is unknown: it may already have consumed provider quota. The examples disable SDK retries.

Status/code What to do
401, AI_GATEWAY_AUTH_REQUIRED Check the token, expiry, revocation and target instance
403, AI_GATEWAY_DISABLED Enable the gateway on the target instance
403, AI_GATEWAY_ORIGIN_FORBIDDEN Call from your backend, not a foreign browser origin
AI_GATEWAY_ACCESS_REFUSED Check the instance’s access/subscription requirements
400, unsupported parameter or effort Remove unsupported fields; use the selected model’s advertised efforts
404/409, AI_GATEWAY_MODEL_UNAVAILABLE Refresh /models and explicitly select an available ID
413, AI_GATEWAY_INPUT_TOO_LARGE Reduce the supplied history; an oversized HTTP body is also refused
429, AI_GATEWAY_BUSY Wait for the active call to finish before trying again
429, AI_GATEWAY_RATE_LIMIT Stop immediate retries and wait for the local minute window
SAFE_STRUCTURED_AI_QUOTA_EXHAUSTED Wait for provider quota recovery; error.resets_at may be null
409, cancellation Treat the call as cancelled; do not resume automatically
502/503, provider/unavailable error Check the account connection and instance health before an explicit retry

An unknown provider reset time stays unknown. Never derive one from a model name or an unrelated provider’s quota schedule.

Using another instance from the application

An external application can call another own instance with that instance’s Base URL and a token created there. Each token belongs to its issuing instance. The gateway currently supplies text completions only. It is not yet an AirCode Ø engine connection for interactive coding sessions: it does not implement Responses, Anthropic Messages or tool calling. A gateway token also cannot log the desktop/mobile client into another instance as its owner.

For AI-assisted integration, see Documentation for AI, the raw Markdown guide, the OpenAPI schema, and the integration skill.

Code examples

Set the three environment variables above before running an example. These snippets are also available in Settings and in the raw Markdown guide.

cURL

Bash, curl and jq. List models first, then use the exact model ID you selected.

set -euo pipefail
# The token is read from standard input, not a command-line argument.
curl --fail-with-body --silent --show-error --location --max-redirs 0 \
  "$AIRCODE_AI_BASE_URL/models" --header @- <<EOF
Authorization: Bearer $AIRCODE_AI_TOKEN
EOF

body=$(jq -n --arg model "$AIRCODE_AI_MODEL" \
  '{model: $model, messages: [{role: "user", content: "Hello!"}]}')
curl --fail-with-body --silent --show-error --location --max-redirs 0 \
  "$AIRCODE_AI_BASE_URL/chat/completions" \
  --header 'Content-Type: application/json' \
  --header @- --data "$body" <<EOF
Authorization: Bearer $AIRCODE_AI_TOKEN
EOF

Python

Install the OpenAI Python SDK 3 with python -m pip install "openai>=3,<4".

import os
from openai import OpenAI, DefaultHttpx2Client

client = OpenAI(
    base_url=os.environ["AIRCODE_AI_BASE_URL"],
    api_key=os.environ["AIRCODE_AI_TOKEN"],
    max_retries=0,
    http_client=DefaultHttpx2Client(follow_redirects=False),
)

for model in client.models.list():
    print(model.id)

response = client.chat.completions.create(
    model=os.environ["AIRCODE_AI_MODEL"],
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)

JavaScript streaming

Node.js and the OpenAI SDK: npm install openai. This is buffered SSE: the complete validated answer arrives at the end.

import OpenAI from "openai";

function required(name) {
  if (!process.env[name]) throw new Error("Set " + name + " first.");
  return process.env[name];
}

const client = new OpenAI({
  baseURL: required("AIRCODE_AI_BASE_URL"),
  apiKey: required("AIRCODE_AI_TOKEN"),
  maxRetries: 0,
  fetchOptions: { redirect: "error" },
});

const stream = await client.chat.completions.create({
  model: required("AIRCODE_AI_MODEL"),
  messages: [{ role: "user", content: "Hello!" }],
  stream: true,
  stream_options: { include_usage: true },
});

try {
  for await (const chunk of stream) {
    process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
    if (chunk.usage) console.error("Tokens:", chunk.usage.total_tokens);
  }
  process.stdout.write("\n");
} finally {
  stream.controller.abort();
}

SDK configuration references:OpenAI Python SDKand OpenAI JavaScript SDK. This gateway supports the subset documented above.