AACSearch
API-Referenz

Authentifizierung

Bearer-Schlüssel mit dem Prefix aac_live_, Scope-Modell, Indexbindung, CORS und die Header jeder Antwort.

Alle Endpunkte unter /api/v1/indexes/*, /api/v1/analytics/*, /api/v1/billing/*, /api/v1/organization/*, /api/v1/admin/*, /api/v1/jobs/*, /api/v1/api-keys/* und /api/v1/recent verlangen einen API-Schlüssel. Öffentlich sind /health, /status, /capabilities, /openapi.json, /embed/* (per Session-Token) und /widget.js.

Schlüssel übermitteln

curl -sS "$AAC_API/indexes/documentation/search?q=preise" \
  -H "Authorization: Bearer aac_live_9f3c2a1bD4eF6gH8iJ0kL2mN4oP6qR8s"

Der Header muss mit Bearer beginnen, und der Schlüssel muss ^aac_(live|test)_[A-Za-z0-9_-]{20,}$ erfüllen. Alles andere wird vor jedem Datenbankzugriff abgelehnt:

{
	"error": {
		"code": "UNAUTHORIZED",
		"message": "Missing or invalid API key",
		"request_id": "req_2f8a1c4e6b9d0e3f5a7c8b1d"
	}
}

Dieselbe 401 kommt für einen formal gültigen, aber unbekannten oder widerrufenen Schlüssel (revokedAt gesetzt). Schlüssel werden als SHA-256-Hash gespeichert; der Klartext existiert nur in der Antwort, die ihn erzeugt hat.

Scopes

Ein Schlüssel trägt eine Liste von Scopes. * erlaubt alles. Die Konsole bietet:

ScopeErlaubt
search:read/search, /suggest, /stats, GET /documents/{id}, Dialoge, Assistent, Answer, Voice, Image, eingeschränkte Schlüssel für Lesezugriffe
documents:readGET /documents/export, GET /snapshots, GET /snapshots/{id}
documents:read_privatePrivate Felder in Treffern, Dokumenten und Export (siehe Private Felder)
documents:writePOST /documents, /documents/bulk, DELETE /documents…, /webhook, /docsearch/preview; zusammen mit settings:write Snapshots anlegen, löschen, wiederherstellen
settings:writePOST /reindex, /scoped-key, GET /conversation-models, POST /api-keys/{keyId}/rotate, Jobs reindex, file_import, snapshot, restore lesen und abbrechen
analytics:readAnalytics lesen (die Übersicht akzeptiert auch search:read)
analytics:writePOST /events (Klicks und Conversions)
billing:read/billing/usage, /billing/wallet, /billing/invoices, /billing/invoices/{id}[.pdf]

Ein fehlender Scope ist eine 403, keine 404 — der Endpunkt existiert, der Schlüssel darf ihn nur nicht nutzen:

curl -sS -X POST "$AAC_API/indexes/documentation/documents" \
  -H "Authorization: Bearer aac_live_…read_only_key…" \
  -H "Content-Type: application/json" \
  -d '{"documents":[{"external_id":"x","content":"y"}]}'
{
	"error": {
		"code": "FORBIDDEN",
		"message": "Missing scope: documents:write",
		"request_id": "req_7b3e9d2a5c8f1a4b6d0e3c7a"
	}
}

Indexbindung

Ein für einen Index erzeugter Schlüssel (indexId gesetzt) erreicht nur diesen Index. Ein Geschwisterindex derselben Organisation liefert:

{
	"error": {
		"code": "FORBIDDEN",
		"message": "API key is scoped to a different index",
		"request_id": "req_4d8c2a6f0b1e3d5c7a9f2b4e"
	}
}

Ein Slug, den es in der Organisation des Schlüssels nicht gibt, liefert 404 INDEX_NOT_FOUND — auch wenn er bei einem anderen Mandanten existiert. Der Mandant wird aus dem Schlüssel bestimmt, nie aus Pfad oder Body.

CORS

Die API authentifiziert per Schlüssel und nutzt keine Cookies, deshalb spiegelt sie den Origin des Aufrufers zurück und erlaubt GET, POST, PUT, DELETE, OPTIONS. Preflight wird vor der Authentifizierung mit 204 beantwortet. Exportierte Header: x-request-id, x-aac-quota-remaining, x-aac-quota-limit.

Für Browser-Schlüssel sollten Sie die erlaubten Origins am Schlüssel in der Konsole einschränken und sich nicht allein auf CORS verlassen.

Response-Header

HeaderBedeutung
x-request-idRequest-ID; auch als request_id im Body
x-ratelimit-limitErlaubte Requests pro Fenster für diesen Schlüssel (Standard 600)
x-ratelimit-remainingVerbleibende Requests im aktuellen Fenster
x-ratelimit-resetReset des Fensters als Unix-Zeit in Sekunden
x-aac-quota-limitIm Tarif enthaltene Einheiten der Metrik dieses Aufrufs
x-aac-quota-remainingVerbleibende Einheiten in der Periode
x-aac-indexIndex, auf den der Aufruf aufgelöst wurde
x-aac-profileVerwendetes Suchprofil oder default
x-aac-charged-centsAus dem Wallet belastete Überschreitung dieses Aufrufs

Lebenszyklus eines Schlüssels

  • Anlegen in der Konsole mit Name, Scopes und optionaler Indexbindung. Das Limit hängt am Tarif: 3 Schlüssel bei Free, 10 bei Pro, 100 bei Enterprise.
  • Rotieren mit POST /api-keys/{keyId}/rotate (Scope settings:write, Body { "grace_days": 7 }) oder im Rotations-Dialog der Konsole. Der Nachfolger erhält dieselben Scopes, Origins und Indexbindung; sein Klartext kommt einmal zurück (201). Der alte Schlüssel funktioniert grace_days Tage weiter (Standard 7, 0–30), danach 401 KEY_ROTATED. Doppelte Rotation: 409 KEY_ALREADY_ROTATED; widerrufene oder abgelaufene Schlüssel: 409 KEY_NOT_ACTIVE. Rotation erweitert nie den Zugriff: Ein Schlüssel kann keinen Nachfolger mit Scopes oder Origins erzeugen, die er selbst nicht hat; ein indexgebundener Schlüssel rotiert nur Schlüssel seines Index; ein Schlüssel kann keinen Schlüssel rotieren, der ihn überdauern würde (403 KEY_LIFETIME_EXCEEDS_CALLER); und ein Schlüssel, der selbst in einem Rotations-Übergangsfenster ist, kann weder Schlüssel rotieren noch eingeschränkte Schlüssel ausstellen (403 KEY_IN_GRACE).
  • Owner werden einmal erinnert, wenn ein Schlüssel innerhalb von 7 Tagen aufhört zu funktionieren.
  • Widerrufen in der Konsole, sofort wirksam: der nächste Request mit diesem Schlüssel ist eine 401. Wird ein Schlüssel in seinem Rotations-Übergangsfenster widerrufen, endet auch das Übergangsfenster.
  • lastUsedAt wird bei jedem authentifizierten Aufruf aktualisiert, veraltete Schlüssel fallen damit in der Konsole auf.

Plattform-Administration

/api/v1/admin/* und POST /billing/invoices/generate sind dem Betreiber vorbehalten: zusätzlich zum API-Schlüssel ist der Header x-platform-admin-token mit dem Wert von SEARCH_PLATFORM_ADMIN_TOKEN nötig. Ohne ihn (oder wenn die Variable fehlt) gibt es 403 FORBIDDEN; der Versuch landet im Audit-Log.

Schlüssel für den Browser

Schicken Sie niemals einen aac_live_…-Schlüssel in den Browser. Nutzen Sie serverseitig POST /indexes/{slug}/scoped-key (Scope settings:write) oder besser POST /embed/session: Es liefert ein kurzlebiges, reines Such-Session-Token (Standard 15 Minuten, höchstens 1 Stunde), das das Widget über den /embed/*-Proxy nutzt — auch ein Engine-Credential erreicht die Seite so nie. Der eingeschränkte Schlüssel hat Mandantenfilter und Trefferlimit eingebaut. Siehe Embed-Session.

On this page