# API keys & endpoints
Source: https://docs.tensormachine.ai/api-keys-and-endpoints

Every Tensor Machine key speaks **two wire formats over one endpoint**: the
OpenAI-compatible Chat Completions API and the Anthropic Messages API. Point your existing
SDK at your workspace's endpoint, drop in the key, and go — no code changes beyond the base
URL.

## 1. Generate an API key

Keys are minted in the console, scoped to a **team**:

- **Personal key** — *API Keys* (top-level): owned by you, revoked when you leave.
- **Team key** — *My Team → API keys*: durable and owner-less, survives teammate churn.

Click **Create key**, and copy the `sk-tm-…` secret **once** — it's shown only at creation
and is never retrievable afterward. A key can't make requests until your workspace has a
positive balance (*Billing → Add funds*).

## 2. Choose a model

Set `model` to a model ID your team is allowed to call. Find the list under
**My Team → Model access** in the console. Model IDs are the stable `tm/…` aliases (e.g.
`tm/qwen3-5-9b`) — the same alias works on both formats.

## 3. Your endpoint

Each workspace has its own base URL (shown on the keys page). The **same key** works on both:

| Format | Base URL | Auth header | Path the SDK calls |
| --- | --- | --- | --- |
| OpenAI-compatible | `https://edge.tensormachine.ai/<org>/v1` | `Authorization: Bearer sk-tm-…` | `/chat/completions` |
| Anthropic Messages | `https://edge.tensormachine.ai/<org>/anthropic` | `x-api-key: sk-tm-…` | `/v1/messages` |

Use the format switcher on the keys page to copy the exact base URL and a ready-to-run
example for either one.

## OpenAI-compatible

```python
from openai import OpenAI

client = OpenAI(
    api_key="sk-tm-...",
    base_url="https://edge.tensormachine.ai/<org>/v1",
)

resp = client.chat.completions.create(
    model="tm/qwen3-5-9b",
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
```

```bash
curl https://edge.tensormachine.ai/<org>/v1/chat/completions \
  -H "Authorization: Bearer sk-tm-..." \
  -H "Content-Type: application/json" \
  -d '{"model":"tm/qwen3-5-9b","messages":[{"role":"user","content":"Hello"}]}'
```

## Anthropic-compatible

The Anthropic SDK sends the key as `x-api-key` — Tensor Machine accepts it. Point `base_url`
at the `/anthropic` endpoint; the SDK appends `/v1/messages`.

```python
from anthropic import Anthropic

client = Anthropic(
    api_key="sk-tm-...",
    base_url="https://edge.tensormachine.ai/<org>/anthropic",
)

msg = client.messages.create(
    model="tm/qwen3-5-9b",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)
print(msg.content)
```

```bash
curl https://edge.tensormachine.ai/<org>/anthropic/v1/messages \
  -H "x-api-key: sk-tm-..." \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"tm/qwen3-5-9b","max_tokens":1024,"messages":[{"role":"user","content":"Hello"}]}'
```

`max_tokens` is **required** on the Messages API (unlike Chat Completions). Streaming works
on both formats — set `stream: true` (OpenAI) or use the SDK's streaming helper (Anthropic).

## Notes

- **One key, both formats.** You don't mint a separate key per SDK — the same `sk-tm-…`
  authenticates on either endpoint.
- **Model aliases don't change** between formats: pass the same `tm/…` id.
- **Budget, rate limits, and model access** apply identically regardless of format — they're
  enforced at the edge on the key, not the wire shape.
