Webhook
Ein Webhook ist eine Konfiguration, die eine vorab festgelegte Aktion automatisch ausführt, wenn in einem Space etwas geschieht (z. B. wenn ein Content erstellt oder veröffentlicht wird). Die Aktion ist eines von zwei Dingen: Sie sendet eine HTTP-Anfrage an eine externe URL (url) oder sie führt ein Script innerhalb des Space aus (script). Sie wird für die Anbindung externer Systeme oder für Automatisierung verwendet. So lässt sich beispielsweise konfigurieren, dass bei jeder Veröffentlichung eines Produkt-Content der interne Benachrichtigungsserver aufgerufen wird oder dass mit einem vorab festgelegten Script nachgelagerte Arbeit ausgeführt wird.
Von url und script geben Sie genau eines an. Beides anzugeben oder beides leer zu lassen wird abgelehnt. Ein Webhook ist in der CMA eine untergeordnete Ressource des Space und basiert auf dem Pfad /spaces/{spaceId}/webhooks.
Ressourcenstruktur
Im Folgenden sehen Sie die Antwort der Einzelabfrage des Webhook "Benachrichtigung bei Produktänderung". Neben sys (Systemeigenschaften) enthält er Konfigurationsfelder wie Sendeziel, abonnierte Ereignisse und Auslösebedingungen.
{
"sys": {
"id": "3trmXRM3RqbgSnifyg7PWhk01Examp",
"type": "Webhook",
"space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
"createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
"createdAt": "2026-06-18T11:30:00.000Z",
"updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
"updatedAt": "2026-06-18T11:30:00.000Z",
"version": 1
},
"name": "Benachrichtigung bei Produktänderung",
"filters": [
{ "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }
],
"headers": [
{ "key": "X-Source", "value": "weegloo", "secret": false }
],
"httpBasicUsername": "dailywear",
"topics": ["Content.Create", "Content.Publish"],
"transformation": { "method": "POST", "contentType": "application/json", "includeBody": true },
"url": "https://api.dailywear.example/webhooks/products",
"activate": true,
"runAs": "HookOwner"
}Wichtige Schlüssel:
sys.id: Eindeutige Kennung des Webhook. Wird im Pfad für Einzelabfrage, Änderung und Löschung als{webhookId}eingesetzt.url: Externe Ziel-URL, die beim Eintreten eines Ereignisses aufgerufen wird. Genau eines von ihr undscriptangeben.script: Verweis auf das Script, das anstelle eines externen Aufrufs ausgeführt wird. Genau eines von ihm undurlangeben. Im Beispiel oben nicht vorhanden. Wird unten unter url und script (genau eines) beschrieben.runAs: Benutzeridentität, unter derscriptausgeführt wird. Wird unten unter runAs beschrieben.topics: Array, das festlegt, welche Ereignisse abonniert werden. Das Format wird unten unter topics beschrieben.filters: Bedingung, unter der ein abonniertes Ereignis tatsächlich ausgelöst wird. Wird unten unter filters beschrieben.transformation: Konfiguration, die die Form der ausgehenden Anfrage (Methode, Body usw.) ändert. Wird unten unter transformation beschrieben.
Systemeigenschaften (sys)
Jeder Webhook führt gemeinsame Systemeigenschaften im sys-Objekt. space, createdBy und updatedBy werden in der Refer-Form ({ "sys": { "id", "type": "Refer", "targetType" } }) angegeben.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
id | string | Eindeutige Kennung der Ressource. |
type | string | Ressourcenart. Bei einem Webhook immer "Webhook". |
space | Refer<Space> | Space, zu dem dieser Webhook gehört. |
createdBy | Refer<User> | Benutzer, der die Ressource erstellt hat. |
createdAt | string (date-time) | Zeitpunkt der Erstellung. |
updatedBy | Refer<User> | Benutzer, der die Ressource zuletzt geändert hat. |
updatedAt | string (date-time) | Zeitpunkt der letzten Änderung. |
version | integer (≥1) | Version der Ressource. Erhöht sich bei jeder Änderung um 1. |
Ein Webhook ist eine Konfigurationsressource und kennt daher kein Konzept der Veröffentlichung. Anders als Content oder Content Type besitzt er keine Veröffentlichungsstatus-Eigenschaften wie publish, archive oder status, sondern nur die version zur Änderungsverfolgung. Das Ein- und Ausschalten erfolgt nicht über Veröffentlichung, sondern wird über das Body-Feld activate gesteuert.
Body-Eigenschaften
Der Body eines Webhook (die Konfigurationswerte, die bei Erstellung und Änderung gesendet werden und in der Antwort zurückkommen) besteht aus den folgenden Feldern.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
name | string (1-64) | ✅ | Name des Webhook. |
url | string (url) | △ | Externe Ziel-URL, die beim Eintreten eines Ereignisses aufgerufen wird. Genau eines von ihr und script. Siehe unten url und script (genau eines). |
script | Refer<Script> | △ | Verweis auf das Script, das anstelle eines externen Aufrufs ausgeführt wird. Genau eines von ihm und url. Siehe unten url und script (genau eines). |
runAs | WebhookRunAs | Benutzeridentität, unter der script ausgeführt wird. HookOwner (Standard) oder EventUser. Siehe unten runAs. | |
activate | boolean | ✅ | Eingeschaltet-Status. Bei false wird auch beim Eintreten eines Ereignisses nichts ausgeführt. |
topics | string[] | ✅ | Array der abonnierten Ereignisse. Siehe unten topics. |
filters | Filter[] | ✅ | Array von Auslösebedingungen. Wenn leer, lösen alle abonnierten Ereignisse aus. Siehe unten filters. |
headers | WebhookHeader[] (0-30) | ✅ | Array von HTTP-Headern, die mit dem url-Aufruf gesendet werden. |
httpBasicUsername | string (1-32) | Benutzername für die HTTP-Basic-Authentifizierung des url-Aufrufs. | |
httpBasicPassword | string (1-32) | Passwort für die HTTP-Basic-Authentifizierung des url-Aufrufs. Nur schreibbar. Erscheint nicht in der Antwort. | |
transformation | Transformation | ✅ | Anpassung der an url ausgehenden Anfrage. Siehe unten transformation. |
Von den mit △ markierten url und script geben Sie genau eines an. Beides anzugeben oder beides leer zu lassen wird abgelehnt.
Jeder Eintrag in headers besteht aus key (erforderlich), value (erforderlich) und secret (optional, boolean). Setzen Sie secret auf true, bleibt dieser Wert im Sendeprotokoll verdeckt (siehe unten WebhookLog). Fragen Sie diesen Webhook jedoch ab, erscheint der Wert im Klartext. Das Einzige, was in der Antwort entfällt, ist httpBasicPassword. Gehen Sie also davon aus, dass ein Wert in einem secret-Header für jede Rolle sichtbar ist, die diesen Webhook lesen darf, und halten Sie diese Rolle eng.
topics
Jeder Eintrag in topics hat das Format {Ressource}.{Aktion}. Beispiel: Content.Create, Content.Publish, Media.Create.
Die Aktion ist entweder eine der folgenden oder das *, das alle Aktionen der Ressource bedeutet (z. B. Content.*).
| Aktion | Bedeutung |
|---|---|
All | Alle Aktionen. |
Create | Erstellung. |
Read | Abfrage. |
Edit | Bearbeitung. |
Save | Speichern (Änderung). Das Änderungsereignis ist Save, nicht Update. |
Delete | Löschung. |
Publish | Veröffentlichung. |
Unpublish | Veröffentlichung zurücknehmen. |
Archive | Archivierung. |
Unarchive | Archivierung aufheben. |
filters
filters ist ein Array, das eingrenzt, welche der abonnierten topics den Webhook tatsächlich auslösen. Jeder Filter hat die folgende Form.
{ "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }doc: Zu vergleichender Feldpfad. Einer vonsys.id,sys.contentType.sys.id,sys.createdBy.sys.id,sys.updatedBy.sys.id.op: Vergleichsoperator. Einer vonEQ,NE,IN,NOT_IN,REGEX,NOT_REGEX.value: Vergleichswert. BeiEQ,NE,REGEX,NOT_REGEXein String, beiIN,NOT_INein String-Array.
Sind mehrere Filter gesetzt, muss die Auslösung alle erfüllen (AND). Ist filters leer, lösen alle Ereignisse der abonnierten topics aus.
transformation
transformation ändert die Form der an url ausgehenden HTTP-Anfrage (gilt nicht für einen Webhook, der script verwendet). Ohne Angabe geht die gesamte Ressourcen-Payload unverändert per Standard-POST hinaus.
| Schlüssel | Typ | Beschreibung |
|---|---|---|
method | string | HTTP-Methode. Einer von GET, POST, PUT, DELETE, PATCH. |
contentType | string | Content-Type des Anfrage-Body. Der Body wird in diesem Format serialisiert (unten). |
body | object | Objekt, das den zu sendenden Body über eine JSON-Pointer-Vorlage zusammensetzt. |
includeBody | boolean | Ob der Body der auslösenden Ressource mitgesendet wird. |
In welchem Format der Body übertragen wird
contentType bestimmt das Serialisierungsformat des Body. Der Vergleich ignoriert Groß- und Kleinschreibung sowie Parameter wie ;charset=… und betrachtet nur den vorderen Teil. Ohne Angabe oder bei leerem Wert wird application/json gesendet. Ist includeBody false oder method GET, wird kein Body gesendet, und dann wird auch kein Content-Type angefügt.
Der Body, den ein Webhook sendet, ist immer ein Objekt. Denn die body-Vorlage ist ein Objekt, und ohne Vorlage geht die gesamte ausgelöste Ressource unverändert hinaus.
Deklarierter contentType | Tatsächlich gesendeter Content-Type | Gesendeter Body |
|---|---|---|
| (ohne Angabe) | application/json | JSON |
application/json | Deklarierter Wert unverändert | JSON |
application/x-www-form-urlencoded | Deklarierter Wert unverändert | product[sku]=TUMBLER-500&product[price]=24000 |
text/plain | application/json | JSON |
Sonstige (z. B. text/xml) | Deklarierter Wert unverändert | JSON |
text/plain kann kein Objekt abbilden, daher wird der Content-Type auf ein Format korrigiert, das es abbilden kann, und der Body so gesendet. Der Header sagt nie etwas anderes aus als der tatsächliche Body. Bei einem Ziel, das den Body als Text empfangen muss, lässt sich das über contentType nicht lösen; prüfen Sie daher den Vertrag der Gegenseite.
form-urlencoded entfaltet Objekte in Klammerschlüssel und Arrays in Indizes.
| Body | Entfaltete Schlüssel und Werte |
|---|---|
{ "product": { "sku": "TUMBLER-500", "price": 24000 } } | product[sku]=TUMBLER-500&product[price]=24000 |
{ "tags": ["kitchen", "insulated"] } | tags[0]=kitchen&tags[1]=insulated |
{ "items": [{ "sku": "TUMBLER-500" }] } | items[0][sku]=TUMBLER-500 |
{ "memo": null } | memo= |
Schlüssel und Werte gehen in UTF-8 prozentcodiert hinaus. Die Tabelle oben zeigt die dekodierte Form, um die Schlüsselstruktur sichtbar zu machen. Enthält ein Wert & oder +, wird dies nicht als Paartrenner oder Leerzeichen missverstanden, sondern unverändert übertragen.
Die Notation, Verschachtelungen in Klammerschlüssel zu entfalten, ist eine weit verbreitete Konvention und keine Vorgabe des Formats selbst. Prüfen Sie, ob die Gegenseite product[sku] zu einem verschachtelten Objekt zurückbildet, und bauen Sie die body-Vorlage mit flachen Schlüsseln auf, wenn sie das nicht tut.
Ein Beispiel für eine transformation, die als Formular sendet.
"transformation": {
"method": "POST",
"contentType": "application/x-www-form-urlencoded",
"includeBody": true,
"body": {
"sku": "{ /payload/fields/sku/ko-KR }",
"price": "{ /payload/fields/price/ko-KR }"
}
}Löst ein Content mit sku gleich TUMBLER-500 und price gleich 24000 aus, geht der Body als sku=TUMBLER-500&price=24000 hinaus.
url und script (genau eines)
Wenn ein Webhook ausgelöst wird, führt er eines von zwei Dingen aus. Wenn Sie url angeben, sendet er eine HTTP-Anfrage an diese externe URL (die Form der Anfrage wird durch transformation, headers und httpBasic* bestimmt). Wenn Sie script angeben, geht er nicht nach außen, sondern führt ein Script innerhalb des Space aus.
url: Externe Ziel-URL (http/https). Blockierte Ziele wie private Netzwerke oder Loopback werden abgelehnt.script: DerReferauf das auszuführende Script.
Sie müssen genau eines von beiden angeben. Beides anzugeben oder beides leer zu lassen wird abgelehnt, und der zurückgegebene Code unterscheidet sich je Pfad (siehe Fehler).
"script": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } }Bei Auslösung wird das Script mit delegierten Berechtigungen ausgeführt, und die Ressourcenberechtigungen je Statement werden zur Laufzeit nicht erneut geprüft. Was erlaubt ist, wird bereits beim Verfassen des Script geprüft. Das detaillierte Ausführungs- und Berechtigungsmodell finden Sie unter Script-Ausführungssemantik, Einschränkungen und Sicherheit.
runAs
runAs legt fest, unter welcher Benutzeridentität script ausgeführt wird. Diese Identität wird zum createdBy/updatedBy jeder Ressource, die während der Ausführung erstellt oder geändert wird, und der Filter createdBy: ":self" innerhalb eines Script wird ebenfalls gegen diese Identität aufgelöst. Es handelt sich nur um die Zuordnung, nicht um eine Berechtigungsgrenze. Was möglich ist, wird durch die Berechtigungsprüfung beim Verfassen des Script bestimmt.
| Wert | Ausführungsidentität |
|---|---|
HookOwner | Benutzer, der den Webhook erstellt hat (sys.createdBy). Standardwert. |
EventUser | Benutzer, der dieses Ereignis (die Änderung) ausgelöst hat, also der sys.updatedBy der ausgelösten Ressource. |
Bei einem Webhook, der nur url verwendet, wird runAs ignoriert. Ohne Angabe ist es HookOwner.
WebhookLog
Jedes Mal, wenn ein Webhook eine Sendung versucht, bleibt ein Protokoll zurück. Es ist nur lesend und hat keine Endpunkte zum Erstellen, Ändern oder Löschen. Der Pfad ist /spaces/{spaceId}/webhooks/{webhookId}/logs.
{
"sys": {
"id": "3trmXRM3RqbgSnifyg7PWhc01Exam",
"type": "WebhookLog",
"space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
"requestId": "3trmXRM3qWnLb7Vd1yPcYs04kKrjq",
"statusCode": 200,
"errors": [],
"eventType": "Create",
"url": "https://api.dailywear.example/webhooks/products",
"requestAt": "2026-06-18T11:35:00.100Z",
"responseAt": "2026-06-18T11:35:00.350Z",
"request": {
"url": "https://api.dailywear.example/webhooks/products",
"method": "POST",
"headers": { "Content-Type": "application/json", "X-Source": "weegloo" },
"body": "{\"sys\":{\"type\":\"Content\"}}"
},
"response": {
"url": "https://api.dailywear.example/webhooks/products",
"headers": { "Content-Type": "application/json" },
"body": "{\"ok\":true}",
"statusCode": 200
},
"createdBy": { "sys": { "id": "3trmXRM3RqbgSnifyg7PWhk01Examp", "type": "Refer", "targetType": "Webhook" } },
"createdAt": "2026-06-18T11:35:00.350Z",
"updatedBy": { "sys": { "id": "3trmXRM3RqbgSnifyg7PWhk01Examp", "type": "Refer", "targetType": "Webhook" } },
"updatedAt": "2026-06-18T11:35:00.350Z"
}
}Alle Werte liegen in sys, und es gibt keine Body-Eigenschaften. Schlüssel ohne Wert entfallen in der Antwort.
Welcher Webhook das Protokoll erzeugt hat, zeigt sys.createdBy. Es ist kein Benutzer, sondern der Refer auf diesen Webhook, und auch sys.updatedBy ist derselbe Webhook.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
id | string | Eindeutige Kennung des Protokolls. |
type | string | Immer "WebhookLog". |
space | Refer<Space> | Space, zu dem dieses Protokoll gehört. |
requestId | string | Verfolgungskennung dieses Sendeversuchs. |
statusCode | integer | HTTP-Statuscode der empfangenen Antwort. |
errors | string[] | Liste der Fehlerursachen. In den Protokollen eines Webhook, der an eine URL sendet, ist sie immer leer (der Statuscode benennt den Fehlschlag). Nur in den Protokollen eines Webhook, der über script ein Script ausführt, steht hier die Fehlermeldung dieses Script. |
eventType | string | Der Aktionsname, der diese Sendung ausgelöst hat (z. B. Create, Publish). Es steht nur die hintere Aktion darin, nicht die in topics geschriebene Form Content.Create. |
url | string | Ziel-URL der Sendung. |
requestAt | string (date-time) | Zeitpunkt, zu dem die Anfrage gesendet wurde. |
responseAt | string (date-time) | Zeitpunkt, zu dem die Antwort empfangen wurde. |
request | object | Die gesendete Anfrage. Der Unteraufbau steht weiter unten. Entfällt bei der Listenabfrage. |
response | object | Die empfangene Antwort. Der Unteraufbau steht weiter unten. Entfällt bei der Listenabfrage. |
createdBy | Refer<Webhook> | Der Webhook, der dieses Protokoll erzeugt hat. |
createdAt | string (date-time) | Zeitpunkt der Protokollerstellung. |
updatedBy | Refer<Webhook> | Identisch mit createdBy. |
updatedAt | string (date-time) | Identisch mit createdAt. |
request und response haben jeweils die folgenden Schlüssel.
request:url(Ziel-URL, an die die Anfrage gesendet wurde) ·method(HTTP-Methode) ·headers(Map der gesendeten Header) ·body(String des gesendeten Body).response:url(URL, von der die Antwort empfangen wurde) ·headers(Map der empfangenen Header) ·body(String des empfangenen Body) ·statusCode(empfangener Statuscode).
Das Protokoll eines Webhook, der über script ein Script ausführt, hat eine andere Form. Da es keine Zieladresse zum Senden gibt, fehlt url, und method in request ist fest "SCRIPT". In body von request steht die Payload, die diese Sendung ausgelöst hat, und in body von response der Wert, den dieses Script zurückgegeben hat (oder die Fehlermeldung).
Der Wert eines Headers mit eingeschaltetem secret wird verdeckt gespeichert. Der tatsächliche Wert bleibt nicht im Protokoll.
Lange Bodys werden gekürzt gespeichert. Maßgeblich sind 65.536 Zeichen für body in request und 8.192 Zeichen für body in response. Ist er länger, werden Anfang und Ende behalten und die Mitte ausgelassen, und an dieser Stelle wird die Anzahl der ausgelassenen Zeichen vermerkt. Ist der Body JSON, werden nur lange String-Werte auf dieselbe Weise gekürzt, damit die Struktur nicht zerbricht; Schlüssel und kurze Werte bleiben unverändert.
Das Kriterium, das Erfolg von Fehlschlag trennt, unterscheidet sich je Anbindungsart. Bei einem Webhook, der an eine URL sendet, ist eine Antwort mit 2xx oder 3xx ein Erfolg. Bei einem Webhook, der über script ein Script ausführt, liegt ein Erfolg vor, wenn statusCode kleiner als 400 ist und errors leer ist. Diese eine Bewertung bestimmt zugleich die Aufbewahrungsdauer unten und die Erfolgsquote im Sendestatus.
Die Listenabfrage gibt request und response nicht mit zurück. Denn der Standardwert von select am Listenendpunkt ist -sys.response,-sys.request. Um auch den Body der gesendeten Anfrage und der empfangenen Antwort zu sehen, verwenden Sie die Einzelabfrage oder geben select selbst an und überschreiben damit diesen Standardwert.
Protokolle erfolgreicher Sendungen verschwinden nach 1 Stunde, Protokolle fehlgeschlagener Sendungen nach 3 Tagen. Ein Feld mit dem Ablaufzeitpunkt gibt es in der Antwort nicht; ist die Zeit gekommen, verschwindet das Protokoll von selbst. Werte, die länger aufbewahrt werden müssen, speichern Sie gesondert auf dem empfangenden Server oder halten sie in dem über script ausgeführten Script als Content fest.
Fehler
Dies sind die Codes, die beim Umgang mit einem Webhook auftreten. Codes, die allen Ressourcen gemeinsam sind, finden Sie unter Gemeinsame Fehler.
| Code | Bedingung |
|---|---|
WGL400042 | Bei der Erstellung (POST) oder der vollständigen Änderung (PUT) wurden url und script beide angegeben oder beide leer gelassen. |
WGL422061 | Bei der Teiländerung (PATCH) wurden url und script beide angegeben oder beide leer gelassen. |
WGL422050 | url verweist auf ein blockiertes Ziel wie ein privates Netzwerk oder Loopback. |
API
Die Basis-URL aller Endpunkte unten ist https://cma.weegloo.com/v1, und im Authorization-Header ist ein Bearer-Token zur Authentifizierung an der CMA erforderlich. Bei Änderung (PUT) und Teiländerung (PATCH) muss zur optimistischen Nebenläufigkeitskontrolle der Header X-Weegloo-Version (die sys.version der aktuellen Ressource) mitgesendet werden.
Verwandte Dokumente
- Content: Body-Daten, die einen Webhook auslösen.
- Media: Dateiressource, die einen Webhook auslösen kann.
- Script: Der deklarative Backend-Endpunkt, der über
scriptausgeführt wird. Enthält das Ausführungs- und Berechtigungsmodell. - SpaceRole: Die Rollenkonfiguration, die Berechtigungen wie die Script-Ausführung (
Execute) enthält.
