AACSearch
API-Referenz

Webhooks

POST /indexes/{slug}/webhook — HMAC-signierter Dokument-Ingest für CMS und ereignisgetriebene Pipelines, mit Fünf-Minuten-Replay-Fenster.

POST /api/v1/indexes/{slug}/webhook

Ein signierter Ingest-Endpunkt für Systeme, die Dokumente nach eigenem Zeitplan pushen: CMS, Publish-Pipeline, Queue-Worker. Der Body trägt die Dokumente, die Signatur beweist die Kenntnis eines gemeinsamen Geheimnisses, und der Mandant kommt aus dem API-Schlüssel — nie aus der Payload.

Erfordert den Scope documents:write.

Signatur

Zwei Pflicht-Header:

HeaderWert
x-aac-timestampUnix-Zeit in Sekunden
x-aac-signatureHMAC-SHA256(secret, "{timestamp}.{rawBody}") als Hex; ein optionales Präfix sha256= wird akzeptiert

Das Geheimnis ist die Index-Einstellung webhookSecret, ersatzweise das installationsweite SEARCH_WEBHOOK_SECRET. Der Zeitstempel darf maximal ±300 Sekunden von der Serverzeit abweichen, was das Replay eines abgefangenen Requests begrenzt.

BODY='{"documents":[{"external_id":"release-1.8","title":"Release 1.8","content":"Semantische Suche ist allgemein verfügbar.","url":"https://example.com/changelog/1-8"}],"action":"upsert"}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')

curl -sS -X POST "$AAC_API/indexes/documentation/webhook" \
  -H "Authorization: Bearer $AAC_KEY" \
  -H "Content-Type: application/json" \
  -H "x-aac-timestamp: $TS" \
  -H "x-aac-signature: sha256=$SIG" \
  --data "$BODY"
{
	"index": "documentation",
	"indexed": 1,
	"failed": [],
	"usage": {
		"plan": "pro",
		"period": "2026-10",
		"resetsAt": "2026-11-01T00:00:00.000Z",
		"documents": { "used": 140, "limit": 50000 },
		"searches": { "used": 18420, "limit": 500000 }
	},
	"request_id": "req_8b0d2f4a6c8e0b2d4f6a8c0e"
}

Die Signatur wird über den rohen Request-Body berechnet, vor jeder erneuten JSON-Serialisierung — Schlüsselreihenfolge und Leerzeichen zählen. In Node.js:

import { createHmac } from "node:crypto";

const rawBody = JSON.stringify({ documents, action: "upsert" });
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = createHmac("sha256", process.env.WEBHOOK_SECRET)
	.update(`${timestamp}.${rawBody}`)
	.digest("hex");

await fetch(`${api}/indexes/documentation/webhook`, {
	method: "POST",
	headers: {
		Authorization: `Bearer ${process.env.AAC_KEY}`,
		"Content-Type": "application/json",
		"x-aac-timestamp": timestamp,
		"x-aac-signature": `sha256=${signature}`,
	},
	body: rawBody,
});

Body

FeldPflichtHinweis
documentsja1–1000 Dokumente, gleiche Struktur wie bei POST /documents
actionneinupsert (Standard), create, update, emplace

Dokumente werden mit source_type webhook importiert, der Lauf landet als webhook.ingest im Audit-Log, inklusive Dokumentzahl und Anzahl der indizierten Dokumente.

Fehlerfälle

StatusCodeUrsache
400INVALID_JSONBody ist kein gültiges JSON — prüfen Sie, was Sie signiert haben
401UNAUTHORIZEDx-aac-timestamp oder x-aac-signature fehlt
401STALE_SIGNATUREZeitstempel außerhalb des 300-Sekunden-Fensters
401INVALID_SIGNATUREHMAC passt nicht zur Payload
422INVALID_DOCUMENTdocuments[] fehlt, ist leer oder enthält mehr als 1000 Einträge
503WEBHOOK_NOT_CONFIGUREDKein webhookSecret am Index und kein SEARCH_WEBHOOK_SECRET am Server
{
	"error": {
		"code": "INVALID_SIGNATURE",
		"message": "Signature does not match the payload",
		"request_id": "req_1d3f5b7a9c1e3d5f7a9b1c3e"
	}
}

Der Signaturvergleich läuft in konstanter Zeit, ein Fast-Treffer verrät also nichts über den erwarteten Wert.

Wiederholungen und Reihenfolge

Der Endpunkt ist nicht von sich aus idempotent — ein wiederholter Request importiert dieselben Dokumente erneut, was bei upsert harmlos ist (gleiche external_id, gleicher Inhalt), aber keine Exactly-once-Semantik liefert. Wenn Sie die brauchen, hängen Sie eine eigene Sequenznummer an metadata und gleichen Sie ab, oder nutzen Sie POST /documents mit Idempotency-Key.

Innerhalb eines Aufrufs werden Dokumente in der empfangenen Reihenfolge indiziert. Über Aufrufe hinweg gibt es keine Reihenfolgegarantie; ein Publisher, der außer der Reihe liefern kann, sollte ein Versionsfeld im Dokument mitführen und serverseitig entscheiden, welche Kopie gewinnt.

On this page