# Authentifizierung

Jeder Aufruf, der ein Modell ausführt oder deine Anfragen liest, benötigt einen API-Schlüssel. Der Katalog (`GET /models`,
`GET /categories`), `POST /quote` und das OpenAPI-Dokument sind öffentlich.

## API-Schlüssel

Erstelle und widerrufe Schlüssel unter [https://doitong.com/developers/dashboard#keys](https://doitong.com/developers/dashboard#keys). Ein Schlüssel sieht aus
wie `doitong_`, gefolgt von 64 Hexadezimalzeichen, und wird nur einmal angezeigt, wenn du ihn erstellst. Sende ihn im
`Authorization`-Header:

```bash
curl https://api.doitong.com/v1/account -H "Authorization: Bearer $DOITONG_API_KEY"
```

`X-API-Key: <key>` funktioniert ebenfalls.

> [!WARNING]
> Bewahre Schlüssel auf deinem Server auf: Jeder, der einen Schlüssel besitzt, kann die API-Credits ausgeben, die dieser ausgeben darf. Wenn ein Schlüssel bekannt wird,
> widerrufe ihn und erstelle einen neuen.

Eine Anfrage ohne Schlüssel erhält `401` mit dem Code `missing_api_key`; ein unbekannter, widerrufener oder abgelaufener Schlüssel erhält ebenfalls `401`.

## Berechtigungsbereiche

Jeder Schlüssel enthält Berechtigungsbereiche. Die Modell-API prüft diese:

| Aktion | Erforderlicher Berechtigungsbereich |
|---|---|
| Modell ausführen, Anfrage abbrechen, Dateien einer Anfrage löschen, Speichereinstellung ändern | `models:run` (Schlüssel mit dem älteren `images:create` oder `videos:create` funktionieren ebenfalls) |
| Upload-URL erstellen | `models:run` oder `media:upload` |
| Anfragen und Konto lesen | `models:read` (ein Schlüssel, der Modelle ausführen darf, kann auch lesen) |

Neue Schlüssel erhalten standardmäßig `models:read` und `models:run`. Ein Aufruf ohne den richtigen Berechtigungsbereich erhält `403` mit dem Code
`insufficient_scope`.

## Credit-Budgets

Ein Schlüssel kann ein eigenes Budget in API-Credits enthalten (1.000 API-Credits = 1 $), das vom Kontoinhaber festgelegt wird: ein Gesamtbudget, ein
tägliches Budget (letzte 24 Stunden) oder beides. Bevor eine Ausführung abgerechnet wird, werden die Kosten mit dem verglichen, was der Schlüssel bereits
über diese API ausgegeben hat (abzüglich Erstattungen). Eine Ausführung, die das Budget überschreiten würde, wird mit `402 budget_exceeded` abgelehnt, und nichts
wird abgerechnet.

> [!IMPORTANT]
> Eine Budgetablehnung ist endgültig: Ein erneuter Versuch hilft nicht, bis der Inhaber das Budget erhöht.

 Ein Schlüssel ohne Budget kann
bis zum API-Guthaben ausgeben. Separat erhält eine Ausführung, die das API-Guthaben nicht decken kann, `402 insufficient_credits`
mit einer `top_up_url`.

`GET https://api.doitong.com/v1/account` zeigt das API-Guthaben und das verbleibende Budget des Schlüssels (beides in API-Credits):

```json 200 OK · Konto
{
  "object": "account",
  "credits": 125000,
  "balance": { "credits": 125000, "usd": "125.00" },
  "top_up_url": "https://doitong.com/developers/dashboard#balance",
  "key": {
    "name": "Production server",
    "prefix": "doitong_3fa9c1e...",
    "scopes": ["models:read", "models:run"],
    "budget_remaining": 50000,
    "rate_limit": 3600,
    "rate_limit_remaining": 3571
  },
  "webhook_signing_secret": "whsec_..."
}
```

`budget_remaining` ist `null`, wenn der Schlüssel kein eigenes Budget hat.

## Ratenlimits

Jeder Schlüssel darf 3600 Anfragen pro Stunde stellen, sofern sein Limit nicht anders festgelegt wurde. Jede authentifizierte Antwort enthält
den aktuellen Status:

| Header | Bedeutung |
|---|---|
| `X-RateLimit-Limit` | Im aktuellen Zeitfenster zulässige Anfragen |
| `X-RateLimit-Remaining` | Im aktuellen Zeitfenster verbleibende Anfragen |
| `X-RateLimit-Reset` | Unix-Zeitpunkt, an dem das Zeitfenster zurückgesetzt wird |

Bei Überschreitung des Limits erhältst du `429` mit einem `Retry-After`-Header (Sekunden). Long Polling mit `?wait=` zählt als eine Anfrage
pro Aufruf, daher ist Warten günstiger als schnelles Polling.

Außerdem gibt es pro Konto ein Limit von 10 laufenden Anfragen (`queued` oder `running`). Der Start einer weiteren Anfrage gibt
`429 too_many_inflight` zurück; starte sie erneut, nachdem eine Anfrage abgeschlossen wurde.
