> For the complete documentation index, see [llms.txt](https://docs.avis.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.avis.xyz/readme.md).

# AVIS Documentation

<button type="button" class="button primary" data-action="search" data-icon="magnifying-glass">Search...</button>

<a class="button secondary" data-icon="rocket-launch">User Guide</a><a href="https://docs.avis.xyz/api-reference/overview" class="button secondary" data-icon="key">API Reference</a><a class="button secondary" data-icon="code">Integrations</a>

&#x20;

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><h4><i class="fa-leaf" style="color:$primary;">:leaf:</i></h4></td><td><strong>Build Without Limits</strong></td><td>The Operating System for AI Applications. Turn ideas into products, impact, and momentum.</td><td><a href="https://www.avis.xyz/">https://www.avis.xyz/</a></td><td><a href="/files/KitG8LpsLqqhBgKFBABX">/files/KitG8LpsLqqhBgKFBABX</a></td></tr><tr><td><h4><i class="fa-server" style="color:$primary;">:server:</i></h4></td><td><strong>One Way In. One Way Out</strong></td><td>Your single connection to the entire world of AI. Instead of juggling providers, managing keys, and rebuilding every time a model changes — connect once, and build with any model through one simple integration. We handle the access, the routing, and the complexity underneath.</td><td><a href="https://www.avis.xyz/gateway">https://www.avis.xyz/gateway</a></td><td><a href="/files/VNydErlWTCZKpOUx0i1J">/files/VNydErlWTCZKpOUx0i1J</a></td></tr><tr><td><h4><i class="fa-terminal" style="color:$primary;">:terminal:</i></h4></td><td><strong>Distribution &#x26; Network</strong></td><td>Unified access, marketplace distribution, and network effects built directly into the operating layer.</td><td><a href="https://www.avis.xyz/app-store">https://www.avis.xyz/app-store</a></td><td><a href="/files/1qvEnQW5b67P9jxjxI3L">/files/1qvEnQW5b67P9jxjxI3L</a></td></tr></tbody></table>

&#x20;

&#x20;

{% columns %}
{% column width="50%" %}

## Get started in minutes

Make your first API call in under 5 minutes.

This quickstart walks through the basic setup: create an account, generate an API key, and create your very first request. The examples use the same request in several languages, so you can start with the one that matches your stack.

{% hint style="info" icon="sparkle" %}
**Customize your first request**

Explain what you're building and let AI tweak your quickstart.

<button type="button" class="button primary" data-action="ask" data-icon="gitbook-assistant">What are you building?</button>
{% endhint %}

{% hint style="warning" icon="life-ring" %}
**Need some help?**

Troubleshoot common issues or ask for help.

<details>

<summary>I get a 401 Unauthorized error</summary>

Check that your API key is present and valid.

Make sure you replaced `YOUR_API_KEY` in the example.

Confirm the `Authorization` header uses `Bearer YOUR_API_KEY`.

</details>

<details>

<summary>I get a 400 Bad Request error</summary>

Check your request body first.

Make sure the JSON is valid and the `message` field is included.

Also confirm you send `Content-Type: application/json`.

</details>

<details>

<summary>The request succeeds, but the result is not what I expect</summary>

Start with the sample payload before testing custom input.

Check the response `status` field to confirm whether the request was only queued.

If you change the payload shape, verify the endpoint accepts those fields.

</details>

<details>

<summary>My local example does not run</summary>

Check that your runtime and dependencies are installed.

For JavaScript, install the SDK before running the example.

For Python, make sure `requests` is available in your environment.

</details>

<button type="button" class="button primary" data-action="ask" data-icon="gitbook-assistant">Explain what's happening...</button>
{% endhint %}

With your first request done, use the guides for deeper setup and the API reference for endpoints and parameters.<br>

<a href="https://www.avis.xyz/gateway" class="button primary" data-icon="rocket-launch">Get started</a> <a href="https://docs.avis.xyz/api-reference/introduction" class="button secondary" data-icon="terminal">API Reference</a>

&#x20;

&#x20;
{% endcolumn %}

{% column width="50%" %}
{% stepper %}
{% step %}

#### Create your API key

Set up your account, then generate an API key for local testing and your first integration.

<a href="https://www.avis.xyz/login" class="button primary">Sign in to AVIS Platform</a>
{% endstep %}

{% step %}

#### Make your first request

Pick an API reference in our documentation, replace `YOUR_API_KEY`, and run.

{% tabs %}
{% tab title="Authentication" %}
{% code overflow="wrap" %}

```typescript
Creating an API key
Sign in at avis.xyz

Go to Settings → API Keys.

Click Create key, give it a name, and save it somewhere safe — the raw key is only shown once at creation time (it can be revealed again later from the same page).

A single account may have a limit on the number of API keys. Creating past the limit returns 403 Forbidden.
```

{% endcode %}
{% endtab %}

{% tab title="Streaming" %}
{% code overflow="wrap" %}

```typescript
## Enabling / disabling streaming

| Surface | How to stream | How to get a single JSON response |
|---|---|---|
| OpenAI (`chat/completions`, `/responses`) | `"stream": true` in the request body | `"stream": false` (default) |
| OpenAI (`images/generations`) | `"stream": true` — only honored when the resolved model's provider supports streamed image events; otherwise the request still completes, just as a single JSON response | `"stream": false` (default) |
| OpenAI (`videos`) | Not applicable — video generation is always async (submit + poll), see [OpenAI compatibility](./openai-compatibility.md) | n/a |
| Anthropic (`messages`) | `"stream": true` in the request body | `"stream": false` (default) |
| Gemini | Call `models/{model}:streamGenerateContent` instead of `models/{model}:generateContent` | Call `:generateContent` |

All streamed responses are sent as `Content-Type: text/event-stream` with `Cache-Control: no-cache, no-transform` and `Connection: keep-alive`.
```

{% endcode %}
{% endtab %}

{% tab title="Usage" %}
{% code overflow="wrap" %}

```md
## Endpoints

| Method | Path | Description |
| --- | --- | --- |
| GET | `/api/compat/v1/usage` | List generation records from `generations` table |

Auth: `Authorization: Bearer <jwt>` or `x-api-key`.

## GET /api/compat/v1/usage

Query fields:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `offset` | `number` | No | Default `0` |
| `limit` | `number` | No | Default `20` |

Response shape:

| Field | Type |
| --- | --- |
| `results[]` | Array of generation rows |
| `results[].id` | `string` |
| `results[].userId` | `string` |
| `results[].apiKeyId` | `string \| undefined` |
| `results[].modality` | `"text" \| "image" \| "video" \| "audio"` |
| `results[].model` | `string` |
| `results[].status` | `"succeeded" \| "failed" \| "aborted" \| "cancelled"` |
| `results[].request` | `object \| undefined` |
| `results[].usage` | `object \| undefined` |
| `results[].usdCost` | `number \| undefined` |
| `results[].durationMs` | `number \| undefined` |
| `results[].createdAt` | `datetime` |
| `total` | `number` |
| `offset` | `number` |
| `limit` | `number` |

This endpoint currently supports paging only and returns compat generation rows.

## Note About `generations` Data

This endpoint returns a **compact usage record**, including `request` payload and `usdCost`.

## Reference: `usage` By Modality (From `generations`)

Based on current real records, the `usage` payload is modality-specific.

### Text

Typical fields:

| Field | Type |
| --- | --- |
| `usage.promptTokens` | `number` |
| `usage.completionTokens` | `number` |
| `usage.totalTokens` | `number` |

### Image

Typical fields:

| Field | Type |
| --- | --- |
| `usage.generatedImages` | `number` |
| `usage.inputTokens` | `number` |
| `usage.outputTokens` | `number` |
| `usage.totalTokens` | `number` |

### Video

Typical fields:

| Field | Type |
| --- | --- |
| `usage.completionTokens` | `number` |
| `usage.totalTokens` | `number` |

The exact `usage` keys can vary by provider/model.

```

{% endcode %}
{% endtab %}

{% tab title="Errors" %}
{% code overflow="wrap" expandable="true" %}

```typescript

400
Bad request — missing/invalid parameters, unsupported model, or the model has no pricing configured
401
Unauthorized — missing, invalid, or inactive API key (see Authentication)
403
Forbidden — credit balance is zero or negative
404
Not found — e.g. polling a video job ID that doesn't exist
429
Too many requests — the API key's owner-configured spend limit (daily/weekly/monthly/total) has been reached
500
Internal server error on the Avis side
502 / 503
The upstream model provider errored or is unavailable
```

{% endcode %}
{% endtab %}

{% tab title="OpenAI Compatibility" %}

### Base URL

```
https://api.avis.xyz/api/openai/v1
```

### Switching an existing app

```typescript
import OpenAI from 'openai'

const client = new OpenAI({
  apiKey: process.env.AVIS_API_KEY,
  baseURL: 'https://api.avis.xyz/api/openai/v1',
})
```

#### `POST /chat/completions`

```typescript
const response = await client.chat.completions.create({
  model: 'openai/gpt-4.1-mini',
  messages: [{ role: 'user', content: 'Hello!' }],
})
console.log(response.choices[0].message.content)
```

#### `POST /images/generations`

```typescript
import { writeFileSync } from 'node:fs'

const response = await client.images.generate({
  model: 'gemini-3-pro-image-preview',
  prompt: 'A simple red apple on a white table, photorealistic',
  n: 1,
  size: '1024x1024',
  response_format: 'b64_json',
})

writeFileSync('output.jpg', Buffer.from(response.data[0].b64_json!, 'base64'))
console.log('Image saved to output.jpg')
```

#### `POST /videos` — async job

```typescript
import { writeFileSync } from 'node:fs'

const job = await client.videos.create({
  model: 'alibaba/happyhorse-1.1',
  prompt: 'A red apple falling from a tree in slow motion, photorealistic',
})
console.log('Job submitted:', job.id, '| status:', job.status)

let video = job
while (video.status !== 'completed' && video.status !== 'failed') {
  await new Promise((r) => setTimeout(r, 3000))
  video = await client.videos.retrieve(job.id)
  console.log('Status:', video.status)
}

if (video.status !== 'completed') {
  throw new Error(`Video generation failed. Status: ${video.status}`)
}

const content = await client.videos.downloadContent(video.id)
writeFileSync('output.mp4', Buffer.from(await content.arrayBuffer()))
console.log('Video saved to output.mp4 (via downloadContent)')
```

{% endtab %}

{% tab title="Anthropic Compatibility" %}

### Base URL

```
https://api.avis.xyz/api/anthropic
```

### Switching an existing app

```typescript
import Anthropic from '@anthropic-ai/sdk'

const client = new Anthropic({
  apiKey: process.env.AVIS_API_KEY,
  baseURL: 'https://api.avis.xyz/api/anthropic',
})
```

Nothing else in your existing Anthropic integration needs to change.

### Endpoints

| Method | Path                         | Streaming | Description                  |
| ------ | ---------------------------- | --------- | ---------------------------- |
| `HEAD` | `/api/anthropic`             | —         | Connectivity probe (no auth) |
| `GET`  | `/api/anthropic/v1/models`   | —         | List available models        |
| `POST` | `/api/anthropic/v1/messages` | ✅         | Messages API                 |

`anthropic-version` and `anthropic-beta` request headers are forwarded to the upstream provider when present — see Authentication.

#### `POST /messages`

```typescript
const response = await client.messages.create({
  model: 'anthropic/claude-sonnet-4-5',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello!' }],
})
console.log(response.content[0].text)
```

{% endtab %}

{% tab title="Gemini Compatibility" %}

### Base URL

```
https://api.avis.xyz/api/gemini
```

> The `@google/genai` SDK appends `/v1beta` to `baseUrl` automatically. Pass `https://api.avis.xyz/api/gemini` — **not** `.../api/gemini/v1beta` — or you'll get a doubled path.

### Switching an existing app

```typescript
import { GoogleGenAI } from '@google/genai'

const ai = new GoogleGenAI({
  apiKey: process.env.AVIS_API_KEY,
  httpOptions: {
    baseUrl: 'https://api.avis.xyz/api/gemini',
  },
})
```

Model IDs use the `google/` prefix, e.g. `google/gemini-2.0-flash`.

### Endpoints

| Method | Path                                                      | Streaming | Description                  |
| ------ | --------------------------------------------------------- | --------- | ---------------------------- |
| `HEAD` | `/api/gemini`                                             | —         | Connectivity probe (no auth) |
| `GET`  | `/api/gemini/v1beta/models`                               | —         | List available models        |
| `POST` | `/api/gemini/v1beta/models/{model}:generateContent`       | —         | Generate content             |
| `POST` | `/api/gemini/v1beta/models/{model}:streamGenerateContent` | ✅         | Generate content, streamed   |

#### `POST /models/{model}:generateContent`

```typescript
const response = await ai.models.generateContent({
  model: 'google/gemini-2.0-flash',
  contents: 'Explain quantum entanglement in one sentence.',
})
console.log(response.text)
```

```json
{
  "candidates": [
    {
      "content": { "parts": [{ "text": "Hello! How can I help you today?" }], "role": "model" },
      "finishReason": "STOP"
    }
  ],
  "usageMetadata": { "promptTokenCount": 2, "candidatesTokenCount": 10 }
}
```

#### `POST /models/{model}:streamGenerateContent`

```typescript
const stream = await ai.models.generateContentStream({
  model: 'google/gemini-2.0-flash',
  contents: 'Explain quantum entanglement in one sentence.',
})

for await (const chunk of stream) {
  process.stdout.write(chunk.text ?? '')
}
```

{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}
{% endcolumn %}
{% endcolumns %}

&#x20;

&#x20;

{% columns %}
{% column width="50%" %}

<figure><img src="/files/fbswVcQHwwAZ5izUYmqa" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column width="50%" valign="middle" %}

## Learn more about the developer platform

Read guides, and learn more about working with the developer platform and integrating it with your own stack.

<a href="/spaces/rBHPLaxmpwZv1eMYtJSj" class="button primary" data-icon="book-open">Integrations</a> <a href="https://docs.avis.xyz/api-reference/introduction" class="button secondary" data-icon="book">API References</a>
{% endcolumn %}
{% endcolumns %}

&#x20;

&#x20;

&#x20;


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.avis.xyz/readme.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
