Webhooks und der Feed über die API¶
Diese Seite richtet sich an alle, die ein eigenes Programm verfolgen lassen, was sich in OS ändert. Sie zeigt, wie Sie den Feed lesen, einen Webhook registrieren, eine Zustellung prüfen und was Sie tun, wenn etwas schiefgeht. Was Ereignisse und Webhooks sind, steht unter Ereignisse und Webhooks. Wie Sie eine Anfrage an OS stellen (Adresse, Anmeldung, Seiten, Fehler), steht unter Die Zugriffs-API.
Den Feed lesen¶
curl -s "$OS/api/v1/organisations/$ORG/events?limit=100" -H "Authorization: Bearer $TOKEN"
{"items": [
{"id": "evt_...", "type": "directory.invitation.created", "organisation_id": "org_...",
"cursor": "41", "created_at": "2026-10-17T09:14:03Z", "refs": {"invitation_id": "inv_..."}}
],
"next_cursor": "41"}
- Ohne
cursorbeginnen Sie beim ältesten Ereignis, das OS noch aufbewahrt. Verarbeiten Sie die Seite, merken Sie sichnext_cursorund fragen Sie beim nächsten Mal mit?cursor=und diesem Wert ab. next_cursorsteht auch auf einer kurzen Seite: Dann zeigt er hinter alles, was OS bis jetzt festgehalten hat, auch hinter die Arten, die Sie mittypesweggelassen haben. Gibt es nichts Neues, erhalten Sie eine leere Seite und denselbennext_cursor; fragen Sie später erneut ab.typesbeschränkt den Feed auf bestimmte Arten:?types=directory.membership.removed.limitist höchstens 100. Eine Seite kann weniger Ereignisse enthalten alslimit, währendnext_cursorweiterläuft: Sie sehen nur, was Sie sehen dürfen.410bedeutet, dass die Ereignisse nach Ihrem Cursor nicht mehr aufbewahrt werden. Lesen Sie den Stand neu ein und beginnen Sie ohne Cursor.
Sie brauchen see auf event.
Einen Webhook registrieren¶
curl -s -X POST "$OS/api/v1/organisations/$ORG/webhooks" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"url": "https://crm.example.com/os-events", "label": "CRM",
"kinds": ["directory.membership.created", "directory.membership.removed"],
"actor_membership_id": "mem_..."}'
{"id": "whk_...", "label": "CRM", "url": "https://crm.example.com/os-events",
"kinds": ["directory.membership.created", "directory.membership.removed"],
"actor_membership_id": "mem_...", "state": "active", "consecutive_failures": 0,
"allowed_actions": ["see", "write", "delete"], "secret": "whsec_..."}
- Speichern Sie
secretsofort. OS zeigt das Geheimnis nur in dieser Antwort, nie wieder. kindsleer bedeutet jede Art, auch Arten, die später hinzukommen.actor_membership_idist das Konto, in dessen Namen der Webhook empfängt: ein aktives Mitglied Ihrer Organisation, das Sie ändern dürfen und von dem Sie alles haben, was es hat.- Eine Organisation hat höchstens 20 Webhooks.
| Antwort | Bedeutung |
|---|---|
201 |
Registriert; Location zeigt auf den Webhook. |
403 |
Sie haben nicht alles, was das Konto hat. |
409 |
Webhooks sind in dieser Umgebung nicht eingeschaltet, oder Ihre Organisation hat schon 20. |
422 |
Die Adresse ist kein https, nennt eine IP-Adresse statt eines Hostnamens, enthält einen Benutzer, ein Passwort oder #, oder der Host führt auf eine private, interne oder gesperrte Adresse (webhook_host_refused); eine Art existiert nicht; das Konto ist kein aktives Mitglied. |
Ändern, ersetzen, entfernen¶
| Anfrage | Was sie tut |
|---|---|
GET .../webhooks |
die Webhooks, ohne Geheimnis |
GET .../webhooks/{id} |
ein Webhook, mit ETag |
PATCH .../webhooks/{id} |
label, url, kinds oder actor_membership_id ändern, mit If-Match: "<Version>"; eine neue Adresse und ein neues Konto prüft OS wie beim Registrieren |
DELETE .../webhooks/{id} |
der Webhook und sein Protokoll sind weg; die Ereignisse bleiben im Feed |
POST .../webhooks/{id}/rotate-secret |
{"overlap_hours": 24}: ein neues Geheimnis, nur in dieser Antwort; das alte signiert so lange mit (0 bis 168 Stunden, 0 ist sofort) |
POST .../webhooks/{id}/enable |
einen fehlerhaften oder ausgeschalteten Webhook wieder aktiv machen; 409, solange das Konto nicht aktiv ist |
POST .../webhooks/{id}/test |
schickt ein Ereignis events.webhook.tested nur an diesen Webhook, in jedem Zustand; 202 mit delivery_id |
Alle diese Anfragen verlangen write auf webhook (Entfernen delete, Lesen see).
Eine Zustellung empfangen¶
OS sendet jedes Ereignis als POST mit dem Ereignis als JSON und diesen Headern:
| Header | Wert |
|---|---|
Content-Type |
application/json |
User-Agent |
artific-os |
Artific-Signature |
t=<unix-sekunden>,v1=<hex>, und während eines Ersetzens ein zweites v1 |
Idempotency-Key |
die ID der Zustellung, bei jedem Versuch dieselbe |
Artific-Event-Id |
die ID des Ereignisses |
Antworten Sie mit einem 2xx, sobald Sie das Ereignis sicher gespeichert haben; erledigen Sie die Arbeit danach. OS wartet höchstens 10 Sekunden auf Ihre Antwort und liest ihren Inhalt nicht. Ein anderer Status, eine Weiterleitung oder keine Antwort gilt als fehlgeschlagen, und OS versucht es erneut.
Sie können dieselbe Zustellung mehr als einmal erhalten, zum Beispiel wenn Ihre Antwort unterwegs verloren ging. Verwerfen Sie eine Zustellung, deren Idempotency-Key Sie schon verarbeitet haben.
Die Signatur prüfen¶
Die Signatur ist der HMAC-SHA256 aus der Zeit, einem Punkt und dem exakten Inhalt, mit dem Geheimnis, als Hexadezimalzahl. Akzeptieren Sie eine Zustellung, wenn einer der v1-Werte stimmt und die Zeit um nicht mehr als fünf Minuten abweicht:
import hashlib, hmac, time
def is_from_os(secret: str, header: str, body: bytes) -> bool:
parts = [part.split("=", 1) for part in header.split(",")]
timestamp = next(value for key, value in parts if key == "t")
expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256).hexdigest()
signed = any(hmac.compare_digest(expected, value) for key, value in parts if key == "v1")
return signed and abs(time.time() - int(timestamp)) <= 300
Prüfen Sie den unveränderten Inhalt, so wie Sie ihn erhalten haben, nicht neu aufgebautes JSON. Dieselbe Funktion prüft auch die Webhooks der KI-Funktionen, die auf dieselbe Weise signiert sind.
Während eines Ersetzens mit Überlappung trägt jede Zustellung zwei v1-Werte, den neuen zuerst. Tragen Sie das neue Geheimnis in Ihr Programm ein, wann es Ihnen passt, solange die Überlappung dauert.
Das Zustellprotokoll¶
curl -s "$OS/api/v1/organisations/$ORG/webhooks/$WEBHOOK/deliveries?state=failed" \
-H "Authorization: Bearer $TOKEN"
Jede Zustellung hat state (queued, sending, delivered, failed oder skipped), attempts, last_status, last_error (timeout, connect, tls, host_refused, redirect), und bei einer übersprungenen Zustellung skipped_reason:
skipped_reason |
Bedeutung |
|---|---|
not_visible |
das Konto darf das Ereignis oder die Sache nicht sehen |
actor_inactive |
das Konto ist nicht mehr aktiv; der Webhook ist ausgeschaltet |
webhooks_off |
Webhooks sind in dieser Umgebung nicht eingeschaltet |
POST .../deliveries/{delivery_id}/redeliver sendet eine abgeschlossene Zustellung erneut, mit demselben Idempotency-Key, solange das Ereignis aufbewahrt wird; 409, wenn sie noch wartet oder gerade verschickt wird. Möchten Sie einen ganzen Zeitraum erneut, lesen Sie den Feed ab Ihrem letzten Cursor.