> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fortapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Two protocols supported: OpenAI-compatible and Anthropic Claude — pick what fits

FortAPI supports **two API protocols simultaneously**: classic OpenAI-compatible and native Anthropic Claude-compatible. The same API key works with both.

<CardGroup cols={2}>
  <Card title="OpenAI protocol" icon="plug">
    `POST /v1/chat/completions` — industry standard, supported by virtually all SDKs and frameworks.
  </Card>

  <Card title="Claude protocol" icon="brain">
    `POST /v1/messages` — native Anthropic format with thinking blocks and MCP support.
  </Card>
</CardGroup>

## Base URL

```
https://www.fortapi.com/v1
```

All endpoints live under `/v1`. Auth via the `Authorization: Bearer sk-...` header.

<Note>
  With the **OpenAI protocol**, `base_url` includes `/v1` (`https://www.fortapi.com/v1`). With the **Anthropic SDK**, set `ANTHROPIC_BASE_URL` to the bare domain **without `/v1`** (`https://www.fortapi.com`) — the SDK appends `/v1/messages` itself, and adding `/v1` yourself causes a 404.
</Note>

***

## OpenAI protocol

Use this protocol if your code already uses the official **OpenAI SDK** or a compatible framework (LangChain, LlamaIndex, Vercel AI SDK, etc.).

### Endpoint

```
POST https://www.fortapi.com/v1/chat/completions
```

### Compatibility

The request/response format matches [OpenAI's Chat Completions API](https://platform.openai.com/docs/api-reference/chat). Supported:

* `messages` (with roles `system` / `user` / `assistant` / `tool`)
* `model` — name of any model in the catalog (Claude/Gemini/Grok included — we convert on the fly)
* `stream: true` for streaming responses (Server-Sent Events)
* `tools` / `tool_choice` for function calling
* `temperature`, `top_p`, `max_tokens` and other parameters

### Example: Python (OpenAI SDK)

```python theme={null}
from openai import OpenAI

client = OpenAI(
    api_key="sk-YOUR_KEY",
    base_url="https://www.fortapi.com/v1",
)

response = client.chat.completions.create(
    model="your-model-name",  # see the pricing page on the main site for available model names
    messages=[
        {"role": "system", "content": "You are a friendly assistant."},
        {"role": "user", "content": "Hello! What can you do?"},
    ],
    temperature=0.7,
)

print(response.choices[0].message.content)
print(f"Tokens used: {response.usage.total_tokens}")
```

### Example: Node.js (OpenAI SDK)

```javascript theme={null}
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "sk-YOUR_KEY",
  baseURL: "https://www.fortapi.com/v1",
});

const response = await client.chat.completions.create({
  model: "your-model-name", // call Claude through OpenAI protocol; see the pricing page on the main site for available model names
  messages: [
    { role: "user", content: "Explain quantum entanglement simply." },
  ],
});

console.log(response.choices[0].message.content);
```

### Example: curl + streaming

Replace `your-model-name` with any model name from the pricing page on the main site.

```bash theme={null}
# replace "your-model-name" with any model name from the pricing page
curl https://www.fortapi.com/v1/chat/completions \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "your-model-name",
    "messages": [{"role": "user", "content": "Write a haiku about code."}],
    "stream": true
  }'
```

***

## Claude protocol

Use this protocol if your code is built on the **Anthropic SDK** or you need Claude-specific features (thinking blocks, native tool calls).

### Endpoint

```
POST https://www.fortapi.com/v1/messages
```

### Compatibility

The request/response format matches [Anthropic's Messages API](https://docs.anthropic.com/claude/reference/messages_post). Supported:

* `messages` array (native Claude format)
* `system` as a separate field
* `model` — Claude model name or any other (we convert into Claude protocol)
* `max_tokens` (required for Claude)
* `stream: true`
* `tools` / `tool_choice`
* `thinking` for reasoning models

### Example: Python (Anthropic SDK)

```python theme={null}
from anthropic import Anthropic

client = Anthropic(
    api_key="sk-YOUR_KEY",
    base_url="https://www.fortapi.com",
)

response = client.messages.create(
    model="your-model-name",  # see the pricing page on the main site for available model names
    max_tokens=1024,
    system="You are a technical expert.",
    messages=[
        {"role": "user", "content": "What is the CAP theorem?"},
    ],
)

print(response.content[0].text)
print(f"Used: input={response.usage.input_tokens}, output={response.usage.output_tokens}")
```

### Example: Node.js (Anthropic SDK)

```javascript theme={null}
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  apiKey: "sk-YOUR_KEY",
  baseURL: "https://www.fortapi.com",
});

const response = await client.messages.create({
  model: "your-model-name", // see the pricing page on the main site for available model names
  max_tokens: 1024,
  messages: [
    { role: "user", content: "Explain Rust's borrow checker." },
  ],
});

console.log(response.content[0].text);
```

### Example: curl

Replace `your-model-name` with any model name from the pricing page on the main site.

```bash theme={null}
# replace "your-model-name" with any model name from the pricing page
curl https://www.fortapi.com/v1/messages \
  -H "x-api-key: sk-YOUR_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "your-model-name",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Write a haiku about code."}]
  }'
```

<Note>
  Anthropic SDK uses the `x-api-key` header instead of `Authorization: Bearer`. FortAPI accepts both on the `/v1/messages` endpoint.
</Note>

***

## Which protocol should I pick?

| Scenario                                            | Use                              |
| --------------------------------------------------- | -------------------------------- |
| Already on OpenAI SDK / LangChain / LlamaIndex      | **OpenAI protocol**              |
| Writing native Anthropic code, need thinking blocks | **Claude protocol**              |
| Want to call Claude from existing OpenAI code       | **OpenAI protocol** (we convert) |
| Want to call a GPT model from Anthropic SDK         | **Claude protocol** (we convert) |

In every case — **same API key**, same per-token price, shared balance.

***

## More usage

The examples below use the OpenAI protocol; for the Claude protocol see the equivalent calls in the respective SDK docs.

### Streaming (consuming SSE)

With `stream: true`, the response is a series of Server-Sent Events: each line starts with `data: ` and ends with a final `data: [DONE]`. The official SDKs parse this for you — just iterate.

<CodeGroup>
  ```python Python theme={null}
  stream = client.chat.completions.create(
      model="your-model-name",  # see the pricing page on the main site for available model names
      messages=[{"role": "user", "content": "Count from 1 to 5"}],
      stream=True,
  )
  for chunk in stream:
      delta = chunk.choices[0].delta.content
      if delta:
          print(delta, end="", flush=True)
  ```

  ```javascript Node.js theme={null}
  const stream = await client.chat.completions.create({
    model: "your-model-name", // see the pricing page on the main site for available model names
    messages: [{ role: "user", content: "Count from 1 to 5" }],
    stream: true,
  });
  for await (const chunk of stream) {
    process.stdout.write(chunk.choices[0]?.delta?.content || "");
  }
  ```
</CodeGroup>

### Tool calling (function calling)

The model decides which function to call and returns the arguments; **you** run the function locally, then send the result back as a `role: "tool"` message, and the model produces the final answer.

```python theme={null}
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "What's the weather in Beijing right now?"}]
resp = client.chat.completions.create(
    model="your-model-name",  # use a tool-calling capable model; see the pricing page
    messages=messages,
    tools=tools,
    tool_choice="auto",
)

msg = resp.choices[0].message
if msg.tool_calls:
    call = msg.tool_calls[0]
    # run the function yourself (mock data here) and send the result back
    messages.append(msg)
    messages.append({
        "role": "tool",
        "tool_call_id": call.id,
        "content": '{"temp": "26°C", "weather": "sunny"}',
    })
    final = client.chat.completions.create(model="your-model-name", messages=messages)
    print(final.choices[0].message.content)
```

### Vision / multimodal

Write a `user` message's `content` as an array and mix in `image_url`. The image can be a URL or a `data:` base64 string:

```python theme={null}
response = client.chat.completions.create(
    model="your-model-name",  # use a vision-capable model; see the pricing page
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "What's in this image?"},
            {"type": "image_url", "image_url": {"url": "https://example.com/cat.jpg"}},
            # base64: {"url": "data:image/jpeg;base64,<BASE64_DATA>"}
        ],
    }],
)
print(response.choices[0].message.content)
```

### Embeddings / images / audio

<CodeGroup>
  ```python Embeddings theme={null}
  emb = client.embeddings.create(
      model="your-model-name",  # use an embedding model; see the pricing page
      input="text to embed",
  )
  print(len(emb.data[0].embedding))
  ```

  ```python Image generation theme={null}
  img = client.images.generate(
      model="your-model-name",  # use an image model; see the pricing page
      prompt="a shiba inu coding at a laptop, flat illustration",
      size="1024x1024",
  )
  print(img.data[0].url)
  ```

  ```bash Speech to text theme={null}
  curl https://www.fortapi.com/v1/audio/transcriptions \
    -H "Authorization: Bearer sk-YOUR_KEY" \
    -F file=@audio.mp3 \
    -F model="your-model-name"
  ```

  ```bash Text to speech theme={null}
  curl https://www.fortapi.com/v1/audio/speech \
    -H "Authorization: Bearer sk-YOUR_KEY" \
    -H "Content-Type: application/json" \
    -d '{"model":"your-model-name","input":"Hello, world","voice":"alloy"}' \
    --output speech.mp3
  ```
</CodeGroup>

***

## All endpoints

| Method | Path                       | Purpose                              |
| ------ | -------------------------- | ------------------------------------ |
| POST   | `/v1/chat/completions`     | OpenAI Chat Completions              |
| POST   | `/v1/messages`             | Claude Messages (Anthropic native)   |
| POST   | `/v1/responses`            | OpenAI Responses API                 |
| POST   | `/v1/embeddings`           | Embeddings (OpenAI compatible)       |
| POST   | `/v1/images/generations`   | Image generation (OpenAI compatible) |
| POST   | `/v1/audio/transcriptions` | Speech to text                       |
| POST   | `/v1/audio/speech`         | Text to speech (TTS)                 |
| POST   | `/v1/rerank`               | Reranking                            |
| POST   | `/v1/moderations`          | Content moderation                   |
| POST   | `/v1/video/generations`    | Video generation                     |
| GET    | `/v1/models`               | List of available models             |
| POST   | `/v1beta/models/*`         | Gemini native protocol               |
| POST   | `/mj/*`                    | Midjourney image generation          |
| POST   | `/suno/*`                  | Suno music generation                |

The full list with current models is on the Pricing page on the main site. Which models each endpoint supports is defined by the Pricing page and the **Models** list in the console.
