# Make your first request

> Create an API key, choose a model, and connect your application in a few clear steps.

> **Before you begin**
> You’ll need an OptimAI account and an available provider for your chosen model. Use non-sensitive prompts; participating providers can access request content.

## 1. Create an API key

Open [API keys](/dashboard/api-keys) in Router and create a key for your application. Copy the secret when it appears and store it securely; it is only shown once. Explicitly enable paid requests for this key before sending inference. Existing keys stay disabled until you opt them in.

Keep the key on your server. Never put it in browser code, a public repository, or a shared screenshot.

## 2. Choose your model

Open the [model catalog](/dashboard/models) and choose a supported API edition. Check its enforced limits and current availability. A listed model does not guarantee eligible provider capacity.

The examples below use `gemma3:1b`. Replace it with the exact edition you intend to use. Auto routing is the default; Router selects the lowest eligible conservative credit reservation and rotates equal rounded reservations. To choose one public computer/model offer, follow [choosing a provider](https://router.optimai.network/docs/choosing-a-provider.md).

## 3. Set your environment

Copy the base URL from [Developer API](/dashboard/developers). It must end in `/v1`.

```bash
export ROUTER_BASE_URL="https://api-router.optimai.network/v1"
read -rsp "Router API key: " ROUTER_API_KEY
export ROUTER_API_KEY
echo
```

The silent prompt keeps the secret out of the command itself. You can instead load it from your server’s secret manager.

For an SDK example, install `openai` with `pip install openai` (Python) or `pnpm add openai` (TypeScript). Run these examples on your server or in a terminal.

## 4. Send a request

Start with a short text message. This example waits for the full response. Each request needs a caller-generated UUID in `Idempotency-Key` and a maximum charge in `X-Max-Charge-Credits` (5 credits by default; you may choose less). Router reserves up to that maximum and charges from the provider's saved USD rates and accepted provider-reported token usage; those counts are not independently verified. A 100-credit Router monthly cap also applies to the account.

1. **Authorization**: Bearer $ROUTER_API_KEY. Keep the key on your server.
2. **Idempotency-Key**: A new UUID for each logical request. Reuse it only to retry that request.
3. **X-Max-Charge-Credits**: Optional lower maximum, as a six-decimal string. 5 credits by default.
4. **JSON body**: The exact model ID and your messages.
5. **POST /chat/completions**: Sent to your ROUTER_BASE_URL, which ends in /v1.

### cURL

```bash
ROUTER_REQUEST_ID="$(uuidgen)" # Reuse this ID if you retry the same request.
curl "$ROUTER_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $ROUTER_API_KEY" \
  -H "Idempotency-Key: $ROUTER_REQUEST_ID" \
  -H "X-Max-Charge-Credits: 5.000000" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemma3:1b",
    "messages": [
      { "role": "user", "content": "Hello!" }
    ]
  }'
```

### Python

```python
import os
from uuid import uuid4
from openai import OpenAI

client = OpenAI(
    base_url=os.environ["ROUTER_BASE_URL"],
    api_key=os.environ["ROUTER_API_KEY"],
)

request_id = str(uuid4()) # Reuse this ID if you retry the same request.
response = client.chat.completions.create(
    model="gemma3:1b",
    messages=[{"role": "user", "content": "Hello!"}],
    extra_headers={
        "Idempotency-Key": request_id,
        "X-Max-Charge-Credits": "5.000000",
    },
)

print(response.choices[0].message.content)
```

### TypeScript

```typescript
import OpenAI from "openai";
import { randomUUID } from "node:crypto";

const client = new OpenAI({
  baseURL: process.env.ROUTER_BASE_URL,
  apiKey: process.env.ROUTER_API_KEY,
});

const requestId = randomUUID(); // Reuse this ID if you retry the same request.
const response = await client.chat.completions.create({
  model: "gemma3:1b",
  messages: [{ role: "user", content: "Hello!" }],
}, {
  headers: { "Idempotency-Key": requestId, "X-Max-Charge-Credits": "5.000000" },
});

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

## 5. Read the response

A successful request returns the model’s message in `choices[0].message.content`. The values below are illustrative.

```json
{
  "model": "gemma3:1b",
  "choices": [{
    "index": 0,
    "message": { "role": "assistant", "content": "Hello!" },
    "finish_reason": "stop"
  }]
}
```

Save the request UUID. If the response is lost or interrupted, read its owner-scoped credit receipt at `GET /v1/credits/requests/{request_id}` before deciding whether to retry. Retrying the **same logical request** must reuse the UUID and body.

> **No provider available?**
> A `503 no_priced_provider_available` response means no eligible priced provider can accept the request now. Respect `Retry-After` and try again later. `503 no_provider_for_length` means no online provider serves a request this long right now; shorten the request instead of retrying immediately. Router does not queue the request or silently switch your model.

## Keep building

Learn how to [stream a response](https://router.optimai.network/docs/streaming.md), or explore the full [chat completions reference](https://router.optimai.network/docs/api/chat-completions.md).
