跳至主要內容

Webhooks 請求 (Webhooks request)

當 webhook 事件觸發時,Logto 會向每個已訂閱該事件的端點發送 POST 請求。完整事件目錄請參閱 Webhooks 事件;本頁說明 Logto 傳送的請求結構。

請求標頭 (Request headers)​

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

可自訂標頭可透過 安全 webhook 設定覆寫。

請求主體概覽 (Request body overview)​

主體為 JSON 物件。其具體結構取決於事件所屬類別:

FamilyEvents觸發時機
使用者流程 (User flow)PostRegister, PostSignIn, PostResetPassword使用者完成由 Experience API 處理的註冊、登入或重設密碼流程時。
資料變更 (Data mutation)User.*, Role.*, Scope.*, Organization.*, OrganizationRole.*, OrganizationScope.*由 Management API 呼叫或 Experience API 上的使用者流程導致底層資料模型變更時。
例外 (Exception)Identifier.Lockout, Message.RateLimited, Grant.LimitExceeded安全事件,例如連續驗證失敗導致帳號鎖定等。

每個類別都包含一組共通欄位。各類別會再加上自身的請求上下文欄位及事件專屬 payload。

共通欄位 (Common fields)​

無論類別,所有 webhook 傳送都會包含:

FieldTypeOptional說明
hookIdstringLogto 中 webhook 設定的識別碼。
deliveryIdstring此次傳送的唯一識別碼,對每個 webhook 與事件唯一,且在自動重試期間保持不變。詳見去重複傳送。
eventstring觸發此次傳送的事件。
createdAtstringPayload 建立時間,ISO 8601 格式。
userAgentstring✅觸發請求的 user-agent。

每個類別還會包含觸發請求的 IP 位址:使用者流程事件為 userIp,資料變更與例外事件為 ip。語意相同,名稱差異僅為相容舊版。

去重複傳送 (Deduplicating deliveries)​

同一個 delivery 可能多次抵達你的端點:Logto 會重試回應狀態為 500 以上的請求,因此即使你的端點已處理請求但回應 5xx(例如前端閘道因處理緩慢回傳 504),該請求仍會再次送達。每次重試都帶有相同的 deliveryId,而新事件或同一事件發送到不同 webhook 則會有新的 deliveryId。請記錄你已處理過的 deliveryId,並略過已知的 payload。

deliveryId 也是記錄此次傳送的稽核日誌條目的 id,因此你的服務回報的值可在 Console 的 webhook 最近請求中開啟,或用 GET /api/logs/:id 取得。

測試 payload 也帶有 deliveryId,因此同一處理器可處理,但測試請求不會被記錄。

使用者流程事件 payload (User flow event payloads)​

事件: PostRegister, PostSignIn, PostResetPassword。

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

FieldTypeOptional說明
interactionEvent'SignIn' | 'Register' | 'ForgotPassword'使用者流程事件型別。分別對應 PostSignIn / PostRegister / PostResetPassword。欄位名稱保留歷史 "interaction" 命名。
sessionIdstring✅此事件的 Session ID(非 Interaction ID),如適用。
userIpstring✅觸發請求的 IP 位址。
userIdstring✅此事件關聯的 User ID,如適用。
userUserEntity✅此事件關聯的使用者實體,如適用。
applicationIdstring✅此事件關聯的 Application ID,如適用。
applicationApplicationEntity✅此事件關聯的應用程式實體,如適用。

實體結構 (Entity shapes)​

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

完整欄位請參閱 使用者與應用程式。

資料變更事件 payload (Data mutation event payloads)​

事件: 所有 User.*, Role.*, Scope.*, Organization.*, OrganizationRole.*, OrganizationScope.* 事件。完整目錄見 Webhooks 事件 → 資料變更 webhook 事件。

主體固定包含:

  • 共通欄位。
  • 一個 ip 欄位,為觸發請求的 IP 位址(可選,已知時提供)。
  • 一個API 上下文,描述變更的觸發方式。根據來源有兩種變體:
  • 一個事件專屬 payload:受影響的實體於 data 欄位,部分事件有額外頂層欄位。詳見事件專屬資料 payload。

Experience API 上下文欄位 (Experience API context fields)​

當變更由 Experience API 上的使用者面向流程觸發時(如註冊時的 User.Created 或個資更新時的 User.Data.Updated)會出現。

FieldTypeOptional說明
interactionEvent'SignIn' | 'Register' | 'ForgotPassword'✅產生變更的使用者流程事件型別。欄位名稱保留歷史 "interaction" 命名。
sessionIdstring✅此事件的 Session ID(非 Interaction ID),如適用。
applicationIdstring✅Application ID,如適用。
applicationApplicationEntity✅應用程式實體,如適用。

Management API 上下文欄位 (Management API context fields)​

當變更由 Management API 呼叫觸發時出現。

FieldTypeOptional說明
pathstring✅觸發此 webhook 的 API 呼叫路徑。
methodstring✅API 呼叫的 HTTP 方法。
statusnumber✅API 呼叫的回應狀態碼。
paramsobject✅API 呼叫的 koa 路徑參數。
matchedRoutestring✅koa 匹配到的路由。Logto 用此欄位比對已啟用的 webhook 事件過濾器。

事件專屬資料 payload (Event-specific data payloads)​

每個資料變更事件都包含頂層 data 欄位,攜帶受影響的實體;若變更無法以單一實體摘要(如刪除與成員變更事件),則為 null。部分事件還有額外頂層欄位,Organization.Membership.Updated 為一例,詳見下文。

使用者事件 (User events)​

EventFieldTypeOptional說明
User.CreateddataUserEntity新建立的使用者實體。
User.Data.UpdateddataUserEntity更新後的使用者實體。
User.Deleteddatanull/

角色事件 (Role events)​

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;
};
EventFieldTypeOptional說明
Role.CreateddataRole新建立的角色實體。
Role.Data.UpdateddataRole更新後的角色實體。
Role.Deleteddatanull/
Role.Scopes.UpdateddataScope[]指派給角色的更新後權限範圍 (scopes)。
Role.Scopes.UpdatedroleIdstring✅指派權限範圍的角色 ID。(僅於建立角色時預先指派權限範圍時提供)

權限(Scope)事件 (Permission (Scope) events)​

EventFieldTypeOptional說明
Scope.CreateddataScope新建立的權限範圍實體。
Scope.Data.UpdateddataScope更新後的權限範圍實體。
Scope.Deleteddatanull/

組織事件 (Organization events)​

type Organization = {
id: string;
name: string;
description?: string;
customData: object;
createdAt: number;
};
EventFieldTypeOptional說明
Organization.CreateddataOrganization新建立的組織實體。
Organization.Data.UpdateddataOrganization更新後的組織實體。
Organization.Deleteddatanull/
Organization.Membership.Updateddatanull/變更內容由頂層 delta 陣列描述。詳見Organization.Membership.Updated payload。
Organization.Membership.Updated payload​

除了共通欄位與適用的 API 上下文欄位(Management API 路由用 Management API 上下文,即時佈建用 Experience API 上下文),Organization.Membership.Updated 事件還會在 payload 頂層(與 event、createdAt 等同層,不在 data 內,該欄位對此事件永遠為 null)帶有 organizationId 及可選的 delta 陣列。

FieldTypeOptional說明
organizationIdstring變更成員的組織 ID。
addedUserIdsstring[]✅此觸發新增的 User ID。未新增使用者或不影響使用者成員時省略。
removedUserIdsstring[]✅此觸發移除的 User ID。未移除使用者時省略。
addedApplicationIdsstring[]✅新增的 Application ID。未新增應用程式或不影響應用程式成員時省略。
removedApplicationIdsstring[]✅移除的 Application ID。未移除應用程式時省略。

四個 delta 陣列皆為可選且附加:對於不預期這些欄位的消費者,既有 payload 結構不變,舊有 data: null 欄位仍會照常輸出。

觸發來源與可能出現的 delta 欄位 (Triggers and which delta fields they may emit)​
觸發來源可能出現的 delta 欄位
POST /organizations/:id/usersaddedUserIds
PUT /organizations/:id/usersaddedUserIds, removedUserIds
DELETE /organizations/:id/users/:userIdremovedUserIds
POST /organizations/:id/applicationsaddedApplicationIds
PUT /organizations/:id/applicationsaddedApplicationIds, removedApplicationIds
DELETE /organizations/:id/applications/:applicationIdremovedApplicationIds
PUT /organization-invitations/:id/status(Accepted)addedUserIds
即時佈建新增使用者至新組織時addedUserIds
空 delta 欄位會被省略(缺席 ≠ 空變更) (Empty deltas are omitted (absent ≠ empty change))​

空的 delta 陣列會完全省略於 payload。例如,PUT /organizations/:id/users 若將成員集合替換為現有集合,實際上沒有變更,payload 僅剩 { organizationId },四個 delta 欄位皆缺席。重新加入已存在成員、已是成員的邀請再接受亦同。

消費者必須將缺席欄位視為「該側無變更」,而非「空變更」。

單一陣列上限(靜默截斷) (Per-array cap (silent truncation))​

每個 delta 陣列上限為5000 筆。若單次 Management API 呼叫新增或移除超過 5000 位使用者(或應用程式),對應陣列會靜默截斷為前 5000 筆。payload 內不會標示已觸發上限。

若你的應用程式會進行大規模批次操作,可能一次影響超過 5000 位成員,請將陣列長度正好為 5000 視為需透過 Management API 重新比對成員:

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

此設計與 GitHub 的 push 事件類似,該事件將 commits 上限設為 20 筆,並引導消費者使用 compare API 取得完整清單。

跳過無實際變更事件 (Skipping no-op events)​

要在消費端跳過無實際變更(無 delta 欄位)的傳送,可依 delta 陣列是否存在過濾:

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

?.length 對 undefined 與 [] 皆為 falsy,因此此判斷式無論欄位缺席或(假設未來)為空陣列都適用。

範例 payload (Example payloads)​

新增使用者(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)比對。

組織角色事件 (Organization role events)​

type OrganizationRole = {
id: string;
name: string;
description?: string;
};
type OrganizationScope = {
id: string;
name: string;
description?: string;
};
EventFieldTypeOptional說明
OrganizationRole.CreateddataOrganizationRole新建立的組織角色實體。
OrganizationRole.Data.UpdateddataOrganizationRole更新後的組織角色實體。
OrganizationRole.Deleteddatanull/
OrganizationRole.Scopes.Updateddatanull/
OrganizationRole.Scopes.UpdatedorganizationRoleIdstring✅指派權限範圍的角色 ID。(僅於建立角色時預先指派權限範圍時提供)

組織權限(Scope)事件 (Organization permission (scope) events)​

EventFieldTypeOptional說明
OrganizationScope.CreateddataOrganizationScope新建立的組織權限範圍實體。
OrganizationScope.Data.UpdateddataOrganizationScope更新後的組織權限範圍實體。
OrganizationScope.Deleteddatanull/

例外事件 payload (Exception event payloads)​

事件: Identifier.Lockout, Message.RateLimited, Grant.LimitExceeded。

於安全事件時觸發,例如連續驗證失敗導致帳號鎖定,或因應用程式同時登入裝置數超過上限而撤銷授權。

每個例外事件都帶有共通欄位及 ip 欄位(結構同資料變更事件)。其餘欄位依事件而異。

Identifier.Lockout​

來自使用者面向流程,因此主體還包含 Experience API 上下文欄位,並加上:

enum SignInIdentifier {
Email = 'email',
Phone = 'phone',
Username = 'username',
}
FieldTypeOptional說明
typeSignInIdentifier使用者的識別型別,如 email、phone 或 username。
valuestring觸發鎖定的使用者識別值。

Message.RateLimited​

來自使用者面向流程,因此主體還包含 Experience API 上下文欄位,並加上:

FieldTypeOptional說明
actionstring被限流的動作,例如 VerificationCodeSend。
recipientstring觸發發送速率限制的 email 或手機號碼。

Grant.LimitExceeded​

當成功授權導致使用者超過應用程式的最大同時驗證裝置數(maxAllowedGrants)時,Logto 會撤銷該應用程式最舊的授權,並觸發此事件。

此事件由 OIDC 授權端點發出,而非 Experience API,因此不包含 interactionEvent 或 sessionId。除共通欄位與 ip 外,主體還包含:

FieldTypeOptional說明
userIdstring被撤銷授權的使用者。
applicationIdstring超過 maxAllowedGrants 限制的應用程式。
applicationApplicationEntity✅應用程式實體。若傳送時無法解析應用程式則省略。
maxAllowedGrantsnumber事件觸發時應用程式設定的上限。
preRevocationActiveGrantCountnumber撤銷前該使用者於此應用程式持有的有效授權數(含剛發出的那筆)。
revokedGrantIdsstring[]實際被撤銷的授權 ID,依舊到新排序。

範例 payload:

{
"hookId": "hook_abc",
"deliveryId": "3nfp8xk1q2z7",
"event": "Grant.LimitExceeded",
"createdAt": "2024-01-01T00:00:00.000Z",
"ip": "192.168.0.1",
"userAgent": "Mozilla/5.0",
"userId": "u_001",
"applicationId": "app_xyz",
"application": {
"id": "app_xyz",
"type": "SPA",
"name": "My app",
"description": "My app description"
},
"maxAllowedGrants": 2,
"preRevocationActiveGrantCount": 3,
"revokedGrantIds": ["grant_001"]
}

傳送說明:

  • 被撤銷的授權紀錄會在撤銷時一併刪除,因此 revokedGrantIds 內的 ID 不再能透過授權查詢端點或 Console 查到——那些僅回傳有效授權。若需後續查詢,請自行保存這些 ID。
  • 僅當實際有授權被撤銷時才會觸發事件。若授權未超過上限則不會產生事件。
  • 每次授權超過上限都會觸發一次,因此使用者若不斷從超過允許數量的裝置登入,會產生多次事件。
  • 傳送採 fire-and-forget:慢速或失敗的端點不會阻擋或影響使用者授權。失敗的傳送會如其他 webhook 一樣記錄於稽核日誌。