跳至主要內容

Webhooks 請求

當 webhook 事件觸發時,Logto 會向每個訂閱的端點發送一個 POST 請求。完整的事件目錄位於 Webhooks 事件;本頁記錄了 Logto 傳送的請求結構

請求標頭

Key可自訂說明
user-agent預設為 Logto (https://logto.io/)
content-type預設為 application/json
logto-signature-sha-256請求主體的簽名。請參閱 保護你的 webhooks

可自訂的標頭可以透過 secure webhook 配置覆蓋。

請求主體概述

主體是一個 JSON 物件。其具體結構取決於事件所屬的類別:

類別事件觸發時機
使用者流程PostRegisterPostSignInPostResetPassword使用者完成由 Experience API 處理的註冊、登入或重設密碼流程。
資料變更User.*Role.*Scope.*Organization.*OrganizationRole.*OrganizationScope.*基礎資料模型被變更 — 透過 Management API 呼叫或 Experience API 上的使用者流程。
例外Identifier.Lockout安全事件 — 例如,帳戶在連續驗證失敗後被鎖定。

每個類別共享一小組通用欄位。然後每個類別會添加其自己的請求上下文欄位以及特定事件的負載。

通用欄位

無論類別如何,每次傳送都會包含:

欄位類型可選備註
hookIdstringLogto 中的 webhook 配置識別符。
eventstring觸發此傳送的事件。
createdAtstring負載創建時間,格式為 ISO 8601。
userAgentstring觸發請求的 user-agent。

每個類別還包括觸發請求的 IP 地址 — 在使用者流程事件中為 userIp 欄位,在資料變更和例外事件中為 ip 欄位。語義相同;歷史名稱差異是為了向後相容。

使用者流程事件負載

事件: PostRegisterPostSignInPostResetPassword

當使用者完成由 Experience API 處理的註冊、登入或重設密碼流程時觸發。除了通用欄位外,主體還包含:

欄位類型可選備註
interactionEvent'SignIn' | 'Register' | 'ForgotPassword'使用者流程事件類型。分別對應 PostSignIn / PostRegister / PostResetPassword。欄位名稱保留歷史上的「interaction」命名。
sessionIdstring此事件的 Session ID(非 Interaction ID),如果適用。
userIpstring觸發請求的 IP 地址。
userIdstring與此事件相關的使用者 ID,如果適用。
userUserEntity與此事件相關的使用者實體,如果適用。
applicationIdstring與此事件相關的應用程式 ID,如果適用。
applicationApplicationEntity與此事件相關的應用程式實體,如果適用。

實體結構

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;
};

請參閱 使用者應用程式 以獲取完整的欄位參考。

資料變更事件負載

事件: User.*Role.*Scope.*Organization.*OrganizationRole.*OrganizationScope.* 下的每個事件 — 請參閱 Webhooks 事件 → 資料變更 hook 事件 以獲取完整目錄。

主體始終包含:

  • 通用欄位
  • 一個 ip 欄位 — 觸發請求的 IP 地址(可選,已知時存在)。
  • 描述變更如何觸發的 API 上下文。根據觸發來源,上下文有兩種變體之一:
  • 事件特定負載 — 在 data 中的受影響實體,以及(對於某些事件)其他頂層欄位。請參閱 事件特定資料負載

Experience API 上下文欄位

當變更由 Experience API 上的使用者面向流程觸發時存在 — 例如,註冊期間的 User.Created 或個人資料更新期間的 User.Data.Updated

欄位類型可選備註
interactionEvent'SignIn' | 'Register' | 'ForgotPassword'產生變更的使用者流程事件類型。欄位名稱保留歷史上的「interaction」命名。
sessionIdstring此事件的 Session ID(非 Interaction ID),如果適用。
applicationIdstring應用程式 ID,如果適用。
applicationApplicationEntity應用程式實體,如果適用。

Management API 上下文欄位

當變更由 Management API 呼叫觸發時存在。

欄位類型可選備註
pathstring觸發此 hook 的 API 呼叫路徑。
methodstringAPI 呼叫的 HTTP 方法。
statusnumberAPI 呼叫的回應狀態碼。
paramsobjectAPI 呼叫的 koa 路徑參數。
matchedRoutestringkoa 匹配的路由。Logto 使用此欄位來匹配啟用的 webhook 事件過濾器。

事件特定資料負載

每個資料變更事件都包含一個頂層的 data 欄位,攜帶受影響的實體,或在變更無法總結為單一實體時(刪除和成員事件)為 null。某些事件還包括 data 之外的事件特定頂層欄位 — Organization.Membership.Updated 就是這樣一個例子,詳見下文。

使用者事件

事件欄位類型可選備註
User.CreateddataUserEntity創建的使用者實體。
User.Data.UpdateddataUserEntity更新的使用者實體。
User.Deleteddatanull/

角色事件

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;
};
事件欄位類型可選備註
Role.CreateddataRole創建的角色實體。
Role.Data.UpdateddataRole更新的角色實體。
Role.Deleteddatanull/
Role.Scopes.UpdateddataScope[]分配給角色的更新權限範圍。
Role.Scopes.UpdatedroleIdstring分配權限範圍的角色 ID。(僅在事件由創建具有預先分配權限範圍的角色觸發時可用。)

權限(範圍)事件

事件欄位類型可選備註
Scope.CreateddataScope創建的權限範圍實體。
Scope.Data.UpdateddataScope更新的權限範圍實體。
Scope.Deleteddatanull/

組織事件

type Organization = {
id: string;
name: string;
description?: string;
customData: object;
createdAt: number;
};
事件欄位類型可選備註
Organization.CreateddataOrganization創建的組織實體。
Organization.Data.UpdateddataOrganization更新的組織實體。
Organization.Deleteddatanull/
Organization.Membership.Updateddatanull/變更由可選的頂層增量陣列描述。請參閱下文的 Organization.Membership.Updated 負載
Organization.Membership.Updated 負載

除了共用欄位以及依觸發來源而定的 API 上下文欄位(Management API 路由對應 Management API 上下文,即時 (JIT) 佈建對應 Experience API 上下文)之外,Organization.Membership.Updated 事件還攜帶一個 organizationId,以及在負載頂層的可選增量陣列(與 eventcreatedAt 等並列,不在 data 中,對於此事件始終為 null)。

欄位類型可選備註
organizationIdstring成員變更的組織。
addedUserIdsstring[]此觸發新增的使用者 ID。當未新增使用者或觸發不影響使用者成員時省略。
removedUserIdsstring[]此觸發移除的使用者 ID。當未移除使用者時省略。
addedApplicationIdsstring[]新增的應用程式 ID。當未新增應用程式或觸發不影響應用程式成員時省略。
removedApplicationIdsstring[]移除的應用程式 ID。當未移除應用程式時省略。

四個增量陣列是可選且附加的 — 它們不會改變對不期望它們的消費者的現有負載結構,並且遺留的 data: null 欄位仍然不變地發出。

觸發器及其可能發出的增量欄位
觸發器可能的增量欄位
POST /organizations/:id/usersaddedUserIds
PUT /organizations/:id/usersaddedUserIdsremovedUserIds
DELETE /organizations/:id/users/:userIdremovedUserIds
POST /organizations/:id/applicationsaddedApplicationIds
PUT /organizations/:id/applicationsaddedApplicationIdsremovedApplicationIds
DELETE /organizations/:id/applications/:applicationIdremovedApplicationIds
PUT /organization-invitations/:id/status (Accepted)addedUserIds
將使用者新增至新組織時的即時 (JIT) 佈建addedUserIds
空增量被省略 — 缺席 ≠ 空變更

空增量陣列會從負載中完全省略。例如,將成員集替換為現有集的 PUT /organizations/:id/users 不會產生實際變更,負載僅簡化為 { organizationId },所有四個增量欄位均缺席。同樣適用於重新添加現有成員、已是成員的使用者重新接受邀請。

消費者必須將缺失欄位視為「該方面無變更」,而不是「空變更」。

每個陣列的上限(靜默截斷)

每個增量陣列的上限為 5000 個條目。當單個 Management API 呼叫在一次操作中新增或移除超過 5000 個使用者(或應用程式)時,對應的增量陣列會靜默截斷為其前 5000 個條目 — 負載中沒有標記表示上限已觸發。

如果你的應用程式執行的管理批量操作可能在一次呼叫中影響超過 5000 個成員,請將正好 5000 個條目的陣列視為信號,通過 Management API 協調權威成員:

  • GET /organizations/:id/users — 完整的使用者成員。
  • GET /organizations/:id/applications — 完整的應用程式成員。

這遵循 GitHub 的 push 事件的相同模式,該事件將 commits 限制為 20 個條目,並指示消費者使用比較 API 獲取完整列表。

跳過無操作事件

每次針對成員路由的 PUT 都會發出事件,無論是否實際改變 — 以便任何狀態替換呼叫至少有一個 webhook 傳送以供審計。要在消費者端跳過無操作傳送,請過濾增量陣列的存在:

if (
payload.addedUserIds?.length ||
payload.removedUserIds?.length ||
payload.addedApplicationIds?.length ||
payload.removedApplicationIds?.length
) {
// 實際成員變更 — 處理它
}

?.length 對於 undefined[] 都是偽值,因此無論欄位是缺席還是(在某個假設的未來)作為空陣列發出,相同的謂詞都是穩健的。

範例負載

新增使用者(POST /organizations/:id/users):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedUserIds": ["u_001"]
}

替換使用者成員集(PUT /organizations/:id/users):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedUserIds": ["u_002"],
"removedUserIds": ["u_001"]
}

移除使用者(DELETE /organizations/:id/users/:userId):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"removedUserIds": ["u_001"]
}

新增應用程式(POST /organizations/:id/applications):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedApplicationIds": ["app_xyz"]
}

重新添加現有成員、無操作 PUT 或已是成員的邀請重新接受(無實際變更):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc"
}

達到 5000 上限的批量操作(靜默截斷):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"removedUserIds": ["u_0001", "u_0002", "/* … 總共正好 5000 個條目 */"]
}

看到正好 5000 個條目的陣列應提示協調 GET /organizations/:id/users(或 /applications)。

組織角色事件

type OrganizationRole = {
id: string;
name: string;
description?: string;
};
type OrganizationScope = {
id: string;
name: string;
description?: string;
};
事件欄位類型可選備註
OrganizationRole.CreateddataOrganizationRole創建的組織角色實體。
OrganizationRole.Data.UpdateddataOrganizationRole更新的組織角色實體。
OrganizationRole.Deleteddatanull/
OrganizationRole.Scopes.Updateddatanull/
OrganizationRole.Scopes.UpdatedorganizationRoleIdstring分配權限範圍的角色 ID。(僅在事件由創建具有預先分配權限範圍的角色觸發時可用。)

組織權限(範圍)事件

事件欄位類型可選備註
OrganizationScope.CreateddataOrganizationScope創建的組織權限範圍實體。
OrganizationScope.Data.UpdateddataOrganizationScope更新的組織權限範圍實體。
OrganizationScope.Deleteddatanull/

例外事件負載

事件: Identifier.Lockout

在安全事件中觸發 — 例如,帳戶在連續驗證失敗後被鎖定。這些事件始終源自使用者面向的流程,因此主體攜帶:

enum SignInIdentifier {
Email = 'email',
Phone = 'phone',
Username = 'username',
}
欄位類型可選備註
typeSignInIdentifier使用者的識別符類型,例如電子郵件、電話或使用者名稱。
valuestring觸發鎖定的使用者識別符值。