# Apigator API - Integration Guide (agent-friendly)

> Agent note: If you are an AI agent wiring up a client for your user, follow this
> file verbatim. Base URL, auth, and model id rules are all below. Do not invent
> endpoints or model names. After setup, call GET /v1/models to confirm access.

Apigator is an OpenAI-compatible AI gateway. Point any OpenAI SDK / client at it,
pass an Apigator API key, and call hundreds of models through one endpoint. Billing
is pay-per-token from the user's Apigator credit balance.

## Base URL

```
https://api.apigator.ai/v1
```

One endpoint for everyone. The environment is determined by the key, not the URL
(Stripe-style). This is the OpenAI-compatible surface only; Claude Code CLI uses a
separate endpoint (see "Claude" below).

## Authentication

Bearer token in the `Authorization` header. The key is an Apigator credits key
(`sk-...`), obtained by the user at https://apigator.ai (Dashboard / Billing). One
key works across all models and draws from the same credit balance.

```
Authorization: Bearer sk-YOUR_APIGATOR_KEY
```

## Getting a key (shortest path)

1. Go to https://apigator.ai and sign in with a **MixerBox ID** (email + a one-time code
   emailed to that address — no password). An autonomous agent needs a readable inbox to
   read the code.
2. A credits key (`sk-...`) is **auto-provisioned** on first sign-in — there is no separate
   "create key" step. Copy it from the Dashboard → **Keys** (Reveal → Copy).
3. The key works immediately for the **free models** (below) at a **$0 balance**.

> **Agent note — you do NOT need a human to top up to start.** A brand-new key has a $0
> balance, which is already enough for the free models. Use them for setup, smoke tests,
> and any workload a free model can handle. Only ask a human to top up if the task
> genuinely needs a *paid* model (e.g. `openai/gpt-5.2`, Claude). Don't block on billing
> when a free model would do.

### Agent self-signup (no browser)

An autonomous agent can register with two API calls instead of driving the sign-in page.
Email verification still applies — a one-time code is sent to your address, so the agent
needs a readable inbox.

1. Request a code:

```bash
curl -X POST https://api.apigator.ai/agent/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com"}'
# -> {"verifyToken":"...","message":"Verification code sent to you@example.com."}
```

2. Read the code from your inbox.

3. Verify and receive your key:

```bash
curl -X POST https://api.apigator.ai/agent/verify \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","code":"123456","verifyToken":"..."}'
# -> {"key":"sk-...","email":"you@example.com","balance":0,"docs":"https://apigator.ai/api.md"}
```

The `sk-...` key is your Apigator API key. Free models work immediately at a $0 balance;
top up only when a task needs a paid model. `/agent/verify` also returns an `accessToken`
(valid ~7 days) for the account endpoint below.

### Agent account status (read-only)

Check your balance/usage with the `accessToken` from `/agent/verify`:

```bash
curl https://api.apigator.ai/agent/account \
  -H "Authorization: Bearer <accessToken from /agent/verify>"
# -> {"balance":9.94,"spent":1.06,"budget":11,
#     "key":{"last4":"aGbQ","createdAt":...,"lastUsedAt":...},"claudeAllowed":true}
```

Read-only — top-ups need a human (a card) at https://apigator.ai. When this returns
`401`, the accessToken expired: just re-run `/agent/signup` + `/agent/verify` (you have
the inbox) for a fresh one.

## Quick start (drop-in OpenAI client)

Python:

```python
from openai import OpenAI

client = OpenAI(base_url="https://api.apigator.ai/v1", api_key="sk-...")

resp = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)
```

Node:

```js
import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://api.apigator.ai/v1", apiKey: "sk-..." });
const r = await client.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Hello!" }],
});
```

curl:

```bash
curl https://api.apigator.ai/v1/chat/completions \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello!"}]}'
```

## Choosing a model id

Model ids are clean `trainer/model` names (the trainer is the model's author — like
OpenRouter), never a serving-provider prefix. Examples: `gpt-4o`, `openai/gpt-5.2`,
`meta-llama/llama-3.3-70b-instruct`, `deepseek/deepseek-chat`, `google/gemini-2.5-flash`,
`z-ai/glm-5`, `nvidia/nemotron-3-nano-30b-a3b`. Routing (which backend actually serves a
model, and cheapest-first fallback) is handled internally — you never pick a provider.

Everything except Claude is open to every key by default. New models become available
automatically.

### Free models (no balance needed)

A few models bill $0 and work on a brand-new key **before you top up** — ideal for a first
smoke test. Just use the `free/` id:

- `free/nemotron-nano-30b`
- `free/nemotron-super-120b`
- `free/gemma-4-31b`

Paid models require a balance (top up in the Dashboard); calling one on a $0 balance
returns a clear budget error.

## Picking a model by capability (video / audio / image input)

Each model in `https://apigator.ai/models-catalog.json` carries a **verified** `capabilities`
object (probed on our gateway, not copied from upstream claims):

```json
"capabilities": { "input": ["text","image","video"], "video": "native", "audio_in": false }
```

- `input` — which inputs the model actually accepts on our gateway.
- `video` — **`native`** (ingests the real video: frames + audio + timing — e.g. Gemini),
  **`frames`** (samples still frames only — picture, NO sound), or **`none`**.
- `audio_in` — whether it processes an audio track.

**To analyse a video WITH speech/sound, use a `video: "native"` model** (e.g.
`google/gemini-3-flash-preview`). A `video: "frames"` model sees pictures only. A model not
listing video in `input` will reject video input. Don't trust a bare "multimodal" label — read
`capabilities`.

## Discover available models

```bash
curl https://api.apigator.ai/v1/models -H "Authorization: Bearer sk-..."
```

Returns the OpenAI-standard `{"data":[{"id":...}]}` list. This is the live superset of
addressable ids; for a few wildcard providers it may include an id the upstream account
has not enabled yet — calling it returns a clear `404 model not available`, so just pick
another.

The authoritative, account-accurate catalog (only ids that actually resolve, with
pricing) is the browsable list at https://apigator.ai/models, backed by
https://apigator.ai/models-catalog.json (stable JSON: `{"models":[{"id","name",
"provider","ctx","in","out"}]}`) — prefer this when programmatically choosing a model.

## Streaming

Standard OpenAI SSE streaming works. Set `"stream": true` and read the
`data:`-prefixed chunks. No special handling required.

## Claude (Anthropic models)

Claude is access-controlled (off by default; granted per user via an allowlist) and
is served on a SEPARATE Anthropic-compatible endpoint for the Claude Code CLI:

```
https://claude.apigator.ai
```

See https://apigator.ai/claude-cli (or /claude-cli.md) for that setup. Calling a
Claude model on this OpenAI endpoint without allowlist access returns
`403 claude_not_allowed`.

## Endpoints by modality

Not everything is chat. Each model on https://apigator.ai/models lists the endpoint it
uses; pick the right one. Same base URL, same Apigator key.

| Modality | Endpoint | Model id example |
|----------|----------|------------------|
| Chat | `POST /v1/chat/completions` | `gpt-4o` |
| Image generation | `POST /v1/images/generations` | `openai/gpt-image-1`, `fal_ai/fal-ai/flux/schnell` |
| Text-to-Speech | `POST /v1/audio/speech` | `elevenlabs-tts` |
| Speech-to-Text | `POST /v1/audio/transcriptions` | `groq/whisper-large-v3` |
| Embeddings | `POST /v1/embeddings` | `openai/text-embedding-3-small` |

## Image generation

```bash
curl https://api.apigator.ai/v1/images/generations \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-image-1","prompt":"a red crocodile mascot","n":1}'
```

Returns the OpenAI-standard `{"data":[{"url":...}]}` (or `b64_json`). Fal models use
`fal_ai/<path>` (e.g. `fal_ai/fal-ai/flux/schnell`). Billed per image, not per token.

## Embeddings

```bash
curl https://api.apigator.ai/v1/embeddings \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/text-embedding-3-small","input":"hello world"}'
```

Returns `{"data":[{"embedding":[...]}]}` (OpenAI standard).

## Audio (TTS, Speech-to-Text, Music)

- Text-to-Speech: `POST /v1/audio/speech`, model `elevenlabs-tts`; `voice` MUST be an
  ElevenLabs voice id (not a name) or it returns 500.
- Speech-to-Text: `POST /v1/audio/transcriptions` (Whisper/AssemblyAI).
- Music: `POST https://litellm.mixerbox.ai/elevenlabs/v1/music`.

Full audio guide (agent-friendly): https://apigator.ai/audio.md

## Video generation

OpenAI-style async Videos API (create job -> poll -> download). Verified working with
Veo 3.1 Fast. Billed per second (Veo 3.1 Fast ~ $0.15/s; min 4s, so ~$0.60/clip).

```bash
# 1) create a job
curl https://api.apigator.ai/v1/videos \
  -H "Authorization: Bearer sk-..." \
  -d '{"model":"gemini/veo-3.1-fast-generate-preview","prompt":"a red crocodile mascot waving","seconds":"4"}'
# -> {"id":"video_...","status":"queued"}

# 2) poll until status == "completed"
curl https://api.apigator.ai/v1/videos/video_... -H "Authorization: Bearer sk-..."

# 3) download the mp4
curl https://api.apigator.ai/v1/videos/video_.../content -H "Authorization: Bearer sk-..." --output out.mp4
```

## Music generation (preview)

PREVIEW. ElevenLabs Music works today as a passthrough:
`POST https://litellm.mixerbox.ai/elevenlabs/v1/music`. Other music models (e.g. Lyria)
are pending integration/access. No OpenAI standard exists for music yet.

## Errors

Standard OpenAI-style JSON error bodies. Common cases:

- `401` - missing or invalid key.
- `403 claude_not_allowed` - Claude not enabled for this key (ask MixerBox to
  allowlist the user).
- `400` - bad request (e.g., a provider-specific constraint such as Perplexity's
  minimum `max_tokens`).

## Notes

- One key, one balance, pay per token. No per-seat fees, no subscription.
- The base URL never changes per environment; keys distinguish environments.
- This file is published at https://apigator.ai/api.md for agents to fetch.
