Webhooks-Anfrage
Wenn ein Webhook-Ereignis ausgelöst wird, sendet Logto eine POST-Anfrage an jeden abonnierten Endpunkt. Der vollständige Ereigniskatalog befindet sich unter Webhooks-Ereignisse; diese Seite dokumentiert die Struktur der Anfrage, die Logto liefert.
Anfrage-Header
| Key | Anpassbar | Hinweise |
|---|---|---|
| user-agent | ✅ | Standardmäßig Logto (https://logto.io/). |
| content-type | ✅ | Standardmäßig application/json. |
| logto-signature-sha-256 | Signatur des Anfragetextes. Siehe Sicherung deiner Webhooks. |
Anpassbare Header können über die sichere Webhook-Konfiguration überschrieben werden.
Überblick über den Anfragetext
Der Text ist ein JSON-Objekt. Seine genaue Struktur hängt davon ab, zu welcher Familie das Ereignis gehört:
| Familie | Ereignisse | Wann es ausgelöst wird |
|---|---|---|
| Benutzerfluss | PostRegister, PostSignIn, PostResetPassword | Ein Benutzer schließt einen Anmelde-, Anmelde- oder Passwortzurücksetzungsfluss ab, der von der Experience API behandelt wird. |
| Datenmutation | User.*, Role.*, Scope.*, Organization.*, OrganizationRole.*, OrganizationScope.* | Das zugrunde liegende Datenmodell wird verändert — durch einen Management API-Aufruf oder durch einen Benutzerfluss in der Experience API. |
| Ausnahme | Identifier.Lockout | Ein Sicherheitsvorfall — zum Beispiel ein Konto, das nach aufeinanderfolgenden fehlgeschlagenen Verifizierungsversuchen gesperrt wurde. |
Jede Familie teilt einen kleinen Satz von gemeinsamen Feldern. Jede Familie fügt dann ihre eigenen Anfragekontextfelder sowie eine ereignisspezifische Nutzlast hinzu.
Gemeinsame Felder
In jeder Lieferung unabhängig von der Familie vorhanden:
| Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|
| hookId | string | Die Webhook-Konfigurationskennung in Logto. | |
| event | string | Das Ereignis, das diese Lieferung ausgelöst hat. | |
| createdAt | string | Die Erstellungszeit der Nutzlast im ISO 8601-Format. | |
| userAgent | string | ✅ | Der User-Agent der auslösenden Anfrage. |
Jede Familie enthält auch die IP-Adresse der auslösenden Anfrage — unter dem Feldnamen userIp für Benutzerflussereignisse und ip für Datenmutations- und Ausnahmeereignisse. Die Semantik ist identisch; der historische Namensunterschied wird aus Gründen der Rückwärtskompatibilität beibehalten.
Nutzlasten von Benutzerflussereignissen
Ereignisse: PostRegister, PostSignIn, PostResetPassword.
Ausgelöst, wenn ein Benutzer einen Anmelde-, Anmelde- oder Passwortzurücksetzungsfluss abschließt, der von der Experience API behandelt wird. Zusätzlich zu den gemeinsamen Feldern enthält der Text:
| Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|
| interactionEvent | 'SignIn' | 'Register' | 'ForgotPassword' | Der Benutzerfluss-Ereignistyp. Entspricht PostSignIn / PostRegister / PostResetPassword. Der Feldname behält die historische "Interaktions"-Benennung bei. | |
| sessionId | string | ✅ | Die Sitzungs-ID (nicht Interaktions-ID) für dieses Ereignis, falls zutreffend. |
| userIp | string | ✅ | Die IP-Adresse der auslösenden Anfrage. |
| userId | string | ✅ | Die Benutzer-ID, die mit diesem Ereignis verknüpft ist, falls zutreffend. |
| user | UserEntity | ✅ | Die Benutzerentität, die mit diesem Ereignis verknüpft ist, falls zutreffend. |
| applicationId | string | ✅ | Die Anwendungs-ID, die mit diesem Ereignis verknüpft ist, falls zutreffend. |
| application | ApplicationEntity | ✅ | Die Anwendungsentität, die mit diesem Ereignis verknüpft ist, falls zutreffend. |
Entitätsstrukturen
type UserEntity = {
id: string;
username?: string;
primaryEmail?: string;
primaryPhone?: string;
name?: string;
avatar?: string;
customData?: object;
identities?: object;
lastSignInAt?: string;
createdAt?: string;
applicationId?: string;
isSuspended?: boolean;
};
enum ApplicationType {
Native = 'Native',
SPA = 'SPA',
Traditional = 'Traditional',
MachineToMachine = 'MachineToMachine',
Protected = 'Protected',
SAML = 'SAML',
}
type ApplicationEntity = {
id: string;
type: ApplicationType;
name: string;
description?: string;
};
Siehe Benutzer und Anwendungen für die vollständige Feldreferenz.
Nutzlasten von Datenmutationsereignissen
Ereignisse: jedes Ereignis unter User.*, Role.*, Scope.*, Organization.*, OrganizationRole.*, OrganizationScope.* — siehe Webhooks-Ereignisse → Datenmutations-Hook-Ereignisse für den vollständigen Katalog.
Der Text enthält immer:
- Die gemeinsamen Felder.
- Ein
ip-Feld — die IP-Adresse der auslösenden Anfrage (optional, vorhanden, wenn bekannt). - Einen API-Kontext, der beschreibt, wie die Änderung ausgelöst wurde. Der Kontext ist eine von zwei Varianten, abhängig von der Auslöserquelle:
- Experience API-Kontext — wenn die Änderung aus einem benutzerorientierten Fluss stammt.
- Management API-Kontext — wenn die Änderung aus einem direkten Management API-Aufruf stammt.
- Eine ereignisspezifische Nutzlast — die betroffene Entität in
dataund (für einige Ereignisse) zusätzliche Felder auf oberster Ebene. Siehe ereignisspezifische Daten-Nutzlasten.
Experience API-Kontextfelder
Vorhanden, wenn die Änderung durch einen benutzerorientierten Fluss in der Experience API ausgelöst wurde — zum Beispiel User.Created während der Anmeldung oder User.Data.Updated während der Profilaktualisierungen.
| Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|
| interactionEvent | 'SignIn' | 'Register' | 'ForgotPassword' | ✅ | Der Benutzerfluss-Ereignistyp, der die Änderung hervorgebracht hat. Der Feldname behält die historische "Interaktions"-Benennung bei. |
| sessionId | string | ✅ | Die Sitzungs-ID (nicht Interaktions-ID) für dieses Ereignis, falls zutreffend. |
| applicationId | string | ✅ | Die Anwendungs-ID, falls zutreffend. |
| application | ApplicationEntity | ✅ | Die Anwendungsentität, falls zutreffend. |
Management API-Kontextfelder
Vorhanden, wenn die Änderung durch einen Management API-Aufruf ausgelöst wurde.
| Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|
| path | string | ✅ | Der Pfad des API-Aufrufs, der diesen Hook ausgelöst hat. |
| method | string | ✅ | Die HTTP-Methode des API-Aufrufs. |
| status | number | ✅ | Der Antwortstatuscode des API-Aufrufs. |
| params | object | ✅ | Die koa-Pfadparameter des API-Aufrufs. |
| matchedRoute | string | ✅ | Die koa-übereinstimmende Route. Logto verwendet dieses Feld, um aktivierte Webhook-Ereignisfilter abzugleichen. |
Ereignisspezifische Daten-Nutzlasten
Jedes Datenmutationsereignis enthält ein oberstes data-Feld, das die betroffene Entität trägt, oder null, wenn die Änderung nicht als einzelne Entität zusammengefasst werden kann (Lösch- und Mitgliedschaftsereignisse). Einige Ereignisse enthalten auch ereignisspezifische Felder auf oberster Ebene über data hinaus — Organization.Membership.Updated ist ein solcher Fall, der unten dokumentiert ist.
Benutzerereignisse
| Ereignis | Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|---|
| User.Created | data | UserEntity | Die erstellte Benutzerentität. | |
| User.Data.Updated | data | UserEntity | Die aktualisierte Benutzerentität. | |
| User.Deleted | data | null | / |
Rollenereignisse
type Role = {
id: string;
name: string;
description: string;
type: 'User' | 'MachineToMachine';
isDefault: boolean;
};
type Scope = {
id: string;
name: string;
description: string;
resourceId: string;
createdAt: number;
};
| Ereignis | Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|---|
| Role.Created | data | Role | Die erstellte Rollenentität. | |
| Role.Data.Updated | data | Role | Die aktualisierte Rollenentität. | |
| Role.Deleted | data | null | / | |
| Role.Scopes.Updated | data | Scope[] | Die aktualisierten Berechtigungen, die der Rolle zugewiesen sind. | |
| Role.Scopes.Updated | roleId | string | ✅ | Die Rollen-ID, der Berechtigungen zugewiesen sind. (Nur verfügbar, wenn das Ereignis durch das Erstellen einer Rolle mit vorab zugewiesenen Berechtigungen ausgelöst wurde.) |
Berechtigung (Scope) Ereignisse
| Ereignis | Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|---|
| Scope.Created | data | Scope | Die erstellte Berechtigungsentität. | |
| Scope.Data.Updated | data | Scope | Die aktualisierte Berechtigungsentität. | |
| Scope.Deleted | data | null | / |
Organisationsevents
type Organization = {
id: string;
name: string;
description?: string;
customData: object;
createdAt: number;
};
| Ereignis | Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|---|
| Organization.Created | data | Organization | Die erstellte Organisationsentität. | |
| Organization.Data.Updated | data | Organization | Die aktualisierte Organisationsentität. | |
| Organization.Deleted | data | null | / | |
| Organization.Membership.Updated | data | null | / | Die Änderung wird durch optionale Delta-Arrays auf oberster Ebene beschrieben. Siehe Organization.Membership.Updated Nutzlast unten. |
Organization.Membership.Updated Nutzlast
Zusätzlich zu den gemeinsamen Feldern und den API-Kontextfeldern, die für die Triggerquelle gelten (Management API-Kontext für Management API-Routen, Experience API-Kontext für die Just-in-Time-Bereitstellung), trägt das Organization.Membership.Updated-Ereignis eine organizationId sowie optionale Delta-Arrays auf oberster Ebene der Nutzlast (neben event, createdAt usw.; nicht innerhalb von data, das für dieses Ereignis immer null ist).
| Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|
| organizationId | string | Die Organisation, deren Mitgliedschaft sich geändert hat. | |
| addedUserIds | string[] | ✅ | Benutzer-IDs, die durch diesen Auslöser neu hinzugefügt wurden. Weggelassen, wenn keine Benutzer hinzugefügt wurden oder wenn der Auslöser die Benutzerzugehörigkeit nicht beeinflusst. |
| removedUserIds | string[] | ✅ | Benutzer-IDs, die durch diesen Auslöser entfernt wurden. Weggelassen, wenn keine Benutzer entfernt wurden. |
| addedApplicationIds | string[] | ✅ | Anwendungs-IDs, die neu hinzugefügt wurden. Weggelassen, wenn keine Anwendungen hinzugefügt wurden oder wenn der Auslöser die Anwendungszugehörigkeit nicht beeinflusst. |
| removedApplicationIds | string[] | ✅ | Anwendungs-IDs, die entfernt wurden. Weggelassen, wenn keine Anwendungen entfernt wurden. |
Die vier Delta-Arrays sind optional und additiv — sie ändern nicht die bestehende Nutzlaststruktur für Verbraucher, die sie nicht erwarten, und das Legacy-Feld data: null wird weiterhin unverändert ausgegeben.
Auslöser und welche Delta-Felder sie möglicherweise ausgeben
| Auslöser | Mögliche Delta-Felder |
|---|---|
POST /organizations/:id/users | addedUserIds |
PUT /organizations/:id/users | addedUserIds, removedUserIds |
DELETE /organizations/:id/users/:userId | removedUserIds |
POST /organizations/:id/applications | addedApplicationIds |
PUT /organizations/:id/applications | addedApplicationIds, removedApplicationIds |
DELETE /organizations/:id/applications/:applicationId | removedApplicationIds |
PUT /organization-invitations/:id/status (Accepted) | addedUserIds |
| Just-in-time Bereitstellung beim Hinzufügen des Benutzers zu einer neuen Organisation | addedUserIds |
Hinweis: Die Just-in-Time-Bereitstellung löst Organization.Membership.Updated nicht für eine Organisation aus, in der der Benutzer bereits Mitglied ist.
Hinweis: Die Just-in-Time-Bereitstellung löst Organization.Membership.Updated nicht für eine Organisation aus, in der der Benutzer bereits Mitglied ist.
Hinweis: Die Just-in-Time-Bereitstellung löst Organization.Membership.Updated nicht für eine Organisation aus, in der der Benutzer bereits Mitglied ist.
Leere Deltas werden weggelassen — abwesend ≠ leere Änderung
Leere Delta-Arrays werden vollständig weggelassen aus der Nutzlast. Zum Beispiel, ein PUT /organizations/:id/users, das die Mitgliedschaftsmenge mit der bestehenden Menge ersetzt, erzeugt keine wirkliche Änderung, und die Nutzlast reduziert sich auf nur { organizationId } mit allen vier Delta-Feldern abwesend. Dasselbe gilt für das erneute Hinzufügen eines bestehenden Mitglieds, das erneute Akzeptieren einer Einladung durch einen Benutzer, der bereits Mitglied ist, der bereits Mitglied ist.
Verbraucher müssen ein fehlendes Feld als "keine Änderung auf dieser Seite" behandeln, nicht als "eine leere Änderung".
Pro-Array-Limit (stille Kürzung)
Jedes Delta-Array ist auf 5000 Einträge begrenzt. Wenn ein einzelner Management API-Aufruf mehr als 5000 Benutzer (oder Anwendungen) in einem Vorgang hinzufügt oder entfernt, wird das entsprechende Delta-Array stillschweigend auf seine ersten 5000 Einträge gekürzt — es gibt keinen Marker in der Nutzlast, dass ein Limit ausgelöst wurde.
Wenn deine Anwendung administrative Massenoperationen durchführt, die plausibel mehr als 5000 Mitglieder in einem Aufruf betreffen können, behandle ein Array von genau 5000 Einträgen als Signal, um die autoritative Mitgliedschaft über die Management API abzugleichen:
GET /organizations/:id/users— vollständige Benutzerzugehörigkeit.GET /organizations/:id/applications— vollständige Anwendungszugehörigkeit.
Dies folgt demselben Muster wie das push-Ereignis von GitHub, das commits auf 20 Einträge begrenzt und Verbraucher auf die Vergleichs-API für die vollständige Liste verweist.
Überspringen von No-Op-Ereignissen
Jeder PUT gegen die Mitgliedschaftsrouten gibt ein Ereignis aus, unabhängig davon, ob sich tatsächlich etwas geändert hat — damit jeder zustandsersetzende Aufruf mindestens eine Webhook-Lieferung zu Prüfzwecken hat. Um No-Op-Lieferungen auf der Verbraucherseite zu überspringen, filtere nach Delta-Array-Präsenz:
if (
payload.addedUserIds?.length ||
payload.removedUserIds?.length ||
payload.addedApplicationIds?.length ||
payload.removedApplicationIds?.length
) {
// echte Mitgliedschaftsänderung — bearbeite sie
}
?.length ist sowohl für undefined als auch für [] falsch, sodass dasselbe Prädikat robust ist, unabhängig davon, ob das Feld fehlt oder (in einer hypothetischen Zukunft) als leeres Array ausgegeben wird.
Beispiel-Nutzlasten
Einen Benutzer hinzufügen (POST /organizations/:id/users):
{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedUserIds": ["u_001"]
}
Die Benutzerzugehörigkeitsmenge ersetzen (PUT /organizations/:id/users):
{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedUserIds": ["u_002"],
"removedUserIds": ["u_001"]
}
Einen Benutzer entfernen (DELETE /organizations/:id/users/:userId):
{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"removedUserIds": ["u_001"]
}
Eine Anwendung hinzufügen (POST /organizations/:id/applications):
{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedApplicationIds": ["app_xyz"]
}
Ein bestehendes Mitglied erneut hinzufügen, No-Op PUT oder erneutes Akzeptieren einer bereits bestehenden Einladung (keine wirkliche Änderung):
{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc"
}
Massenoperation, die das 5000-Limit erreicht (still gekürzt):
{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"removedUserIds": ["u_0001", "u_0002", "/* … genau 5000 Einträge insgesamt */"]
}
Das Sehen eines Arrays von genau 5000 Einträgen sollte einen abgleichenden GET /organizations/:id/users (oder /applications) auslösen.
Organisationsrollenereignisse
type OrganizationRole = {
id: string;
name: string;
description?: string;
};
type OrganizationScope = {
id: string;
name: string;
description?: string;
};
| Ereignis | Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|---|
| OrganizationRole.Created | data | OrganizationRole | Die erstellte Organisationsrollenentität. | |
| OrganizationRole.Data.Updated | data | OrganizationRole | Die aktualisierte Organisationsrollenentität. | |
| OrganizationRole.Deleted | data | null | / | |
| OrganizationRole.Scopes.Updated | data | null | / | |
| OrganizationRole.Scopes.Updated | organizationRoleId | string | ✅ | Die Rollen-ID, der Berechtigungen zugewiesen sind. (Nur verfügbar, wenn das Ereignis durch das Erstellen einer Rolle mit vorab zugewiesenen Berechtigungen ausgelöst wurde.) |
Organisationsberechtigung (Scope) Ereignisse
| Ereignis | Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|---|
| OrganizationScope.Created | data | OrganizationScope | Die erstellte Organisationsberechtigungsentität. | |
| OrganizationScope.Data.Updated | data | OrganizationScope | Die aktualisierte Organisationsberechtigungsentität. | |
| OrganizationScope.Deleted | data | null | / |
Ausnahmeereignis-Nutzlasten
Ereignisse: Identifier.Lockout.
Ausgelöst bei Sicherheitsvorfällen — zum Beispiel, ein Konto, das nach aufeinanderfolgenden fehlgeschlagenen Verifizierungsversuchen gesperrt wurde. Diese Ereignisse stammen immer aus einem benutzerorientierten Fluss, daher enthält der Text:
- Die gemeinsamen Felder.
- Das
ip-Feld (gleiche Struktur wie bei Datenmutationsereignissen). - Die Experience API-Kontextfelder.
- Die unten stehenden ausnahmespezifischen Felder.
enum SignInIdentifier {
Email = 'email',
Phone = 'phone',
Username = 'username',
}
| Feld | Typ | Optional | Anmerkungen |
|---|---|---|---|
| type | SignInIdentifier | Der Identifikatortyp des Benutzers, z. B. E-Mail, Telefon oder Benutzername. | |
| value | string | Der Identifikatorwert des Benutzers, der die Sperrung ausgelöst hat. |