# REST-API

Die REST-API unter `https://app.miovea.com/api/v1` bietet dieselben Operationen wie der MCP-Server, für Integrationen ohne KI-Agent. Die vollständige Referenz steht unter `/api/v1/openapi.json` (OpenAPI 3.1) und `/api/v1/docs`.

## Zugang

- **API-Key der Organisation:** `Authorization: Bearer mio_live_…` für Produktion, `mio_test_…` für die Dev-Umgebung. Ein Admin erzeugt den Key in der App unter Einstellungen, Reiter **KI-Zugriff**, Abschnitt **API-Keys**; der Klartext erscheint genau einmal. Der Key gehört der Organisation, nicht der Person, die ihn erzeugt hat.
- **Scopes:** `<domain>:read`, `<domain>:write` (schließt `read` ein) und `<domain>:destroy` für endgültige Operationen. Spezialrechte stehen ausdrücklich als Scope: `dispatch:send`, `settings:manage`, `members:manage`, `billing:manage`, `agents:manage`, `api_keys:manage`. Die Domäne einer Operation nennt ihr Vertrag (`domain`); `jobs.get` und `changes.list` liegen in `system`.
- Schreibzugriffe über API-Keys unterliegen der Agenten-Richtlinie der Organisation; Versand läuft im Namen des Standardabsenders.
- Agenten können statt eines Keys ihr OAuth-Access-Token mit Scope `user:org:read` senden.

## Routen

- **Ressourcen-Routen** leiten sich aus dem Key ab: `customers.list` ist `GET /customers`, `customers.create` ist `POST /customers`, `preinquiries.get` ist `GET /preinquiries/{preinquiry_id}`, `send_packages.send` ist `POST /send-packages/{send_package_id}/send`. Jede Route nennt ihre Operation in `x-operation-key`. Die Antwort ist die Ausgabe der Operation; schreibende Aufrufe liefern zusätzlich den Header `X-Change-Set-Id`.
- **Generischer Aufruf:** `POST /api/v1/operations/{key}/invoke` mit dem Input der Operation als JSON-Body. Antwort `{ data, change_set_id?, replayed? }`.
- **Katalog:** `GET /api/v1/operations?q=<stichwort>` sucht Operationen, `GET /api/v1/operations/{key}` und `GET /api/v1/operations/describe?keys=a,b` liefern Verträge; diese drei und die OpenAPI-Datei sind ohne Anmeldung lesbar. `GET /api/v1/operations/context` liefert Organisation, Rolle, Richtlinie und die wichtigsten Verträge, `GET /api/v1/operations/guides/{topic}` die Guides.

## Beispiele

Kunden suchen:

```
curl -H "Authorization: Bearer mio_live_…" \
  "https://app.miovea.com/api/v1/customers?search=m%C3%BCller&limit=20"
```

Kunden anlegen, wiederholbar ohne Dublette:

```
curl -X POST https://app.miovea.com/api/v1/customers \
  -H "Authorization: Bearer mio_live_…" \
  -H "Idempotency-Key: kunde-mustermann-1980-04-12" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Erika","last_name":"Mustermann","date_of_birth":"1980-04-12"}'
```

Sendepaket versenden, erst nach Zustimmung des Nutzers zur Vorschau:

```
curl -X POST https://app.miovea.com/api/v1/send-packages/{send_package_id}/send \
  -H "Authorization: Bearer mio_live_…" \
  -H "Idempotency-Key: versand-{send_package_id}" \
  -H "X-Confirm: true"
```

## Idempotenz, Bestätigung, Hintergrundaufträge

- Schreibende Aufrufe brauchen den Header `Idempotency-Key`, eindeutig je beabsichtigter Änderung. Eine Wiederholung mit demselben Key liefert dieselbe Antwort mit `Idempotent-Replayed: true`. Derselbe Key mit anderem Body ergibt `idempotency_conflict`.
- Operationen mit `requires_confirmation: true` im Vertrag antworten ohne `X-Confirm: true` mit 409 `confirmation_required` und `details.preview` (Absender, Empfänger, Betreff, Anhänge oder betroffene Daten). Erst nach Zustimmung mit `X-Confirm: true` wiederholen.
- Hintergrundaufträge antworten mit 202 und `Location: /api/v1/jobs/{job_id}`; dort den Stand abfragen (`jobs.get`, Scope `system:read`).
- `expected_revision` im Body schützt `update`- und `patch`-Operationen vor parallelen Änderungen (409 `conflict`).

## Fehlerformat

Fehler kommen als `application/problem+json` (RFC 9457):

```json
{
  "type": "https://app.miovea.com/problems/confirmation_required",
  "title": "Bestätigung erforderlich",
  "status": 409,
  "detail": "Diese Aktion muss ausdrücklich bestätigt werden.",
  "code": "confirmation_required",
  "request_id": "req_…",
  "hint": "details.preview dem Nutzer zeigen und nach Zustimmung mit Header X-Confirm: true (oder confirm: true im Body) wiederholen.",
  "details": { "preview": { … } }
}
```

`code` ist immer kleingeschrieben und entspricht den Codes unter [MCP-Server anbinden](/wiki/erste-schritte/mcp-anbinden). `errors` nennt bei `validation_error` jeden ungültigen Pfad. Zusätzlich gibt es 403 `insufficient_scope`: dem Key fehlt der Scope in `required_scope`.

## Grenzen

- Rate-Limit je Key (Standard 120 Aufrufe pro Minute), mit OAuth-Token je Agent und Nutzer (300 pro Minute); Header `RateLimit` und `RateLimit-Policy`, bei 429 `Retry-After`.
- Request-Body höchstens 2 MB (`payload_too_large`). Dateien laufen nie durch die API: `documents.upload.init` liefert eine Upload-URL für HTTP `PUT`.
- Jede Anfrage steht im Request-Log der Organisation; Schreibvorgänge erscheinen im Verlauf mit Kanal „API“.
