Guild audit logs
An audit log entry records one change made to a guild and the account that made it. It has a numeric action type, the ID of the thing changed, an option map, and a list of before-and-after values. Only List guild audit logs reads them.
Audit log reason
Section titled “Audit log reason”An audit-capable route accepts the X-Audit-Log-Reason request header, listed with the other standard request headers. Fluxer reads the value verbatim and never percent-decodes it, so a caller that percent-encodes the reason stores and reads back the percent-encoded form.
Fluxer trims the value. A value that is blank before trimming, empty after it, or longer than 512 characters after it counts as no reason at all. None of the three fails the request, so a reason that misses the bound is dropped and the operation still succeeds.
The operation writes the accepted reason onto its entry, returns it as the entry reason field, and sends it in the Guild Audit Log Entry Create Dispatch.
Guild audit log response object
Section titled “Guild audit log response object”One page of audit history together with the accounts and webhooks it references. Only audit_log_entries is paginated.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| audit_log_entries1 | array[guild audit log entry object] | The page of entries this request returned |
| users2 | array[partial user object] | The accounts the returned entries name |
| webhooks3 | array[audit log webhook object] | The webhooks a returned webhook action targets |
1 The page ordering is defined by the query parameters of the request that produced it
2 Deduplicated by user ID, and has no user named only by an option field or by a change value
3 One object for each distinct webhook that a returned webhook action targets and that still exists, so a deleted webhook resolves to no object
users holds the actor of every returned entry and, for an action whose target_id names an account, that account as well. An account that can no longer be resolved is still returned, as the deleted-account representation with the username DeletedUser, the discriminator 0000, the global name Deleted User, a null avatar, a null avatar colour, and flags of 0.
Guild audit log entry object
Section titled “Guild audit log entry object”One recorded guild change. An entry is immutable once written, except for a run of message deletion entries, which List guild audit logs can replace with a single consolidated entry. The entry ID is a snowflake, so it has the exact creation time.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the entry, whose snowflake timestamp is the time it was written |
| action_type | integer | Audit action value that identifies the recorded operation |
| user_id1 | snowflake | The ID of the user that performed the action |
| target_id2 | ?string | The ID of the affected entity |
| reason?3 | string | The audit log reason recorded with the operation |
| options?4 | audit log options object | The context fields this audit action records |
| changes?5 | array[audit log change object] | The fields the mutation changed |
1 Every entry has the acting user ID, and an entry produced by consolidation has the actor of the consolidated run
2 A decimal snowflake string for every action except INVITE_CREATE and INVITE_DELETE, where it is the invite code, and null for MESSAGE_BULK_DELETE
3 The field is omitted when the operation recorded no reason, and an entry written by consolidation never has one
4 The field is omitted when the action recorded no option key that this registry publishes
5 The field is omitted when the action records no field change, so it is never returned as an empty array
Example
Section titled “Example”{ "id": "1501314428688998184", "action_type": 24, "user_id": "1489002177550843905", "target_id": "1489002177550843906", "reason": "Nickname violated the rules", "changes": [{"key": "nick", "old_value": "spam bot", "new_value": null}]}Audit actions
Section titled “Audit actions”The Value column is the numeric action_type, which is also the value the action_type query filter accepts. Each description names what target_id identifies and which audit log options the action records. The overwrite options are id, type, and channel_id. The invite options are max_age, max_uses, temporary, channel_id7, and inviter_id7.
| Value | Name | Description |
|---|---|---|
| 1 | GUILD_UPDATE1 | Guild settings or ownership were changed. target_id is the guild, and the action records no options |
| 10 | CHANNEL_CREATE | Guild channel was created. target_id is the channel, and the action records type |
| 11 | CHANNEL_UPDATE | Guild channel was changed. target_id is the channel, and the action records type |
| 12 | CHANNEL_DELETE | Guild channel was deleted. target_id is the channel, and the action records type |
| 13 | CHANNEL_OVERWRITE_CREATE | Channel permission overwrite was created. target_id is the role or member, and the action records the overwrite options |
| 14 | CHANNEL_OVERWRITE_UPDATE | Channel permission overwrite was changed. target_id is the role or member, and the action records the overwrite options |
| 15 | CHANNEL_OVERWRITE_DELETE | Channel permission overwrite was deleted. target_id is the role or member, and the action records the overwrite options |
| 20 | MEMBER_KICK2 | Member was removed by a moderator. target_id is the user, and the action records no options |
| 21 | MEMBER_PRUNE3 | Inactive members were pruned. target_id is nothing, and the action records no options |
| 22 | MEMBER_BAN_ADD | Guild ban was created or replaced. target_id is the user, and the action records delete_member_days4 |
| 23 | MEMBER_BAN_REMOVE | Guild ban was removed. target_id is the user, and the action records no options |
| 24 | MEMBER_UPDATE5 | Guild member state was changed. target_id is the user, and the action records no options |
| 25 | MEMBER_ROLE_UPDATE5 | One role was added to or removed from a member. target_id is the user, and the action records no options |
| 26 | MEMBER_MOVE6 | Member voice session was moved to another channel. target_id is the user, and the action records channel_id and count |
| 27 | MEMBER_DISCONNECT6 | Member voice session was disconnected. target_id is the user, and the action records channel_id and count |
| 28 | BOT_ADD | Bot was added to the guild. target_id is the user, and the action records temporary |
| 30 | ROLE_CREATE | Role was created. target_id is the role, and the action records no options |
| 31 | ROLE_UPDATE | Role was changed. target_id is the role, and the action records no options |
| 32 | ROLE_DELETE | Role was deleted. target_id is the role, and the action records no options |
| 40 | INVITE_CREATE | Invite was created. target_id is the invite code, and the action records the invite options |
| 41 | INVITE_UPDATE8 | Invite was changed. target_id is the invite code, and the action records no options |
| 42 | INVITE_DELETE | Invite was deleted. target_id is the invite code, and the action records the invite options |
| 50 | WEBHOOK_CREATE | Webhook was created. target_id is the webhook, and the action records channel_id7 |
| 51 | WEBHOOK_UPDATE | Webhook was changed. target_id is the webhook, and the action records channel_id7 |
| 52 | WEBHOOK_DELETE | Webhook was deleted. target_id is the webhook, and the action records channel_id7 |
| 60 | EMOJI_CREATE | Emoji was created. target_id is the emoji, and the action records no options |
| 61 | EMOJI_UPDATE | Emoji was changed. target_id is the emoji, and the action records no options |
| 62 | EMOJI_DELETE | Emoji was deleted. target_id is the emoji, and the action records no options |
| 72 | MESSAGE_DELETE | Single message was deleted by a moderator. target_id is the message, and the action records channel_id |
| 73 | MESSAGE_BULK_DELETE9 | Several messages were deleted in one operation. target_id is nothing, and the action records channel_id and count |
| 74 | MESSAGE_PIN | Message was pinned. target_id is the message, and the action records channel_id and message_id |
| 75 | MESSAGE_UNPIN | Message was unpinned. target_id is the message, and the action records channel_id and message_id |
| 90 | STICKER_CREATE | Sticker was created. target_id is the sticker, and the action records no options |
| 91 | STICKER_UPDATE | Sticker was changed. target_id is the sticker, and the action records no options |
| 92 | STICKER_DELETE | Sticker was deleted. target_id is the sticker, and the action records no options |
1 Recorded by Modify guild, by Modify guild custom invite URL, and by Transfer guild ownership, and target_id is the guild in every case
2 A kick entry is always recorded with no change list, so the removed membership state is not published through the entry
3 The value is defined by the wire contract and is accepted by the action_type filter, and no current guild operation records it
4 The option is always recorded. Its value is the legacy delete_message_days body field of Create or replace guild ban, which defaults to 0, so a ban that used delete_message_seconds or sent no body at all records "0"
5 The entry has no options, so a member role change does not name the role it added or removed. The caller reads that from the guild member change fields
6 count is always 1. channel_id is the destination channel for a move and the vacated channel for a disconnect
7 The option is recorded only when the recorded entity has that value, so an invite with no channel or no inviter records neither, and a webhook with no channel records no option at all
8 The filter accepts this value, and no current guild operation records this action
9 A bulk deletion entry is recorded either by a bulk message deletion operation or by the consolidation described under List guild audit logs
Audit log options object
Section titled “Audit log options object”Every field is present only for the actions listed against it in the audit actions registry. Only the keys in this registry are published, and the response omits options entirely when an entry recorded none of them.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| channel_id | string | The decimal ID of the channel the action concerns |
| count1 | number | The number of entities the action affected |
| delete_member_days2 | string | The whole days of the banned member’s messages the ban deleted |
| id | string | The decimal ID of the role or member an overwrite applies to |
| integration_type3 | number | The type of the integration the entry names |
| message_id | string | The decimal ID of the single message the action concerns |
| members_removed3 | number | The number of memberships the action removed |
| role_name3 | string | The name of the role the action concerns |
| type4 | number | The channel type, or the permission overwrite type |
| inviter_id | string | The decimal ID of the user that created the invite |
| max_age | number | The configured invite lifetime in seconds |
| max_uses | number | The configured maximum use count |
| temporary | boolean | Whether the recorded entity is temporary |
| uses3 | number | The invite use count recorded with the action |
1 The value is the length of the consolidated run for MESSAGE_BULK_DELETE and is always 1 for the two voice actions
2 Read from the legacy delete_message_days body field of Create or replace guild ban, so a ban that supplied only delete_message_seconds records "0"
3 The field is defined by the wire contract and no current guild operation records it
4 The value is a channel type for the three channel actions and a permission overwrite type for the three overwrite actions
Audit log change object
Section titled “Audit log change object”One field a mutation changed, with the value on each side of the change.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| key1 | string | The name of the field that changed, drawn from the change fields of the entity the action targets |
| old_value?2 | audit log change value | The value the field held before the mutation |
| new_value?2 | audit log change value | The value the field holds after the mutation |
1 A change whose key is ip is never published through this resource, and changes is omitted entirely when no other change remains
2 A creation has only new_value, a deletion has only old_value, and a modification has both, so a change object always has at least one of the two
A change value is a string, a JSON number, a boolean, null, an array of strings, an array of numbers, or an object with added and removed string arrays. The last shape comes only from the permissions_diff key of a role modification.
Change fields
Section titled “Change fields”Each table below names the fields an action of that family can record.
Guild change fields
Section titled “Guild change fields”Recorded by GUILD_UPDATE.
| Field | Type | Description |
|---|---|---|
| guild_id1 | string | The decimal ID of the guild itself |
| name | string | The name the guild was given by this change (1-100 characters) |
| owner_id | string | The decimal ID of the guild owner |
| vanity_url_code | ?string | The configured custom invite code, or null when the guild has none |
| icon_hash | ?string | The guild icon hash, or null when the guild has no icon |
| banner_hash | ?string | The guild banner hash, or null when the guild has no banner |
| banner_width | ?number | The guild banner width in pixels, or null when the guild has no banner |
| banner_height | ?number | The guild banner height in pixels, or null when the guild has no banner |
| splash_hash | ?string | The guild splash hash, or null when the guild has no splash |
| splash_width | ?number | The guild splash width in pixels, or null when the guild has no splash |
| splash_height | ?number | The guild splash height in pixels, or null when the guild has no splash |
| splash_card_alignment | number | The splash card alignment recorded with the change |
| embed_splash_hash | ?string | The guild embed splash hash, or null when the guild has no embed splash |
| embed_splash_width | ?number | The guild embed splash width in pixels, or null when the guild has no embed splash |
| embed_splash_height | ?number | The guild embed splash height in pixels, or null when the guild has no embed splash |
| features2 | array[string] | The guild features held at this side of the change, in ascending order |
| verification_level | number | The verification level recorded with the change |
| mfa_level | number | The MFA level recorded with the change |
| nsfw_level | number | The NSFW level recorded with the change |
| nsfw | boolean | Whether the guild is marked age restricted |
| content_warning_level | number | The guild content warning level recorded with the change |
| content_warning_text | ?string | The configured content warning text, or null when the guild sets none |
| explicit_content_filter | number | The guild explicit content filter level recorded with the change |
| default_message_notifications | number | The default message notification level recorded with the change |
| system_channel_id | ?string | The decimal ID of the configured system channel, or null when the guild sets none |
| system_channel_flags | number | The system channel flags mask recorded with the change |
| rules_channel_id | ?string | The decimal ID of the configured rules channel, or null when the guild sets none |
| afk_channel_id | ?string | The decimal ID of the configured AFK voice channel, or null when the guild sets none |
| afk_timeout | number | The AFK timeout in seconds |
| disabled_operations | number | The disabled guild operations mask recorded with the change |
| member_count | number | The member count recorded with the mutation |
| message_history_cutoff | ?ISO8601 timestamp | The configured message history cutoff, or null when the guild sets none |
1 The field holds the same value on both sides of every guild action, so it never produces a change object
2 Fluxer sorts the array by string value on both sides of the comparison, so a change object appears only when a feature was added or removed
Channel change fields
Section titled “Channel change fields”Recorded by CHANNEL_CREATE, CHANNEL_UPDATE, and CHANNEL_DELETE.
| Field | Type | Description |
|---|---|---|
| channel_id | string | The decimal ID of the channel itself |
| type | number | The channel type recorded with the change |
| name | ?string | The name the channel was given by this change |
| topic | ?string | The topic the channel was given by this change, or null when it has none |
| parent_id | ?string | The decimal ID of the parent category, or null when the channel sits at the top level |
| position | number | The position of the channel among its siblings |
| nsfw | ?boolean | Whether the channel is marked age restricted, or null when it has no override |
| content_warning_level | number | The content warning level recorded with the change |
| content_warning_text | ?string | The configured content warning text, or null when the channel sets none |
| rate_limit_per_user | number | The slowmode interval in seconds |
| user_limit | ?number | The configured voice occupancy limit |
| voice_connection_limit | ?number | The configured per-user voice connection limit |
| bitrate | ?number | The voice bitrate in bits per second |
| rtc_region | ?string | The pinned voice region, or null when the channel is routed automatically |
| permission_overwrite_count1 | number | The number of permission overwrites the channel has |
1 Only the count is recorded. An individual overwrite mutation records its own permission overwrite entry
Permission overwrite change fields
Section titled “Permission overwrite change fields”Recorded by the three channel overwrite actions. Every value in this family is a string.
| Field | Type | Description |
|---|---|---|
| id | string | The decimal ID of the role or member the overwrite applies to |
| type | string | The decimal permission overwrite type |
| allow | string | The decimal permission mask the overwrite grants |
| deny | string | The decimal permission mask the overwrite denies |
Guild member change fields
Section titled “Guild member change fields”Recorded by MEMBER_UPDATE and MEMBER_ROLE_UPDATE.
| Field | Type | Description |
|---|---|---|
| user_id | string | The decimal ID of the member itself |
| nick | ?string | The nickname the member holds in this guild, or null when none is set |
| roles | array[string] | The assigned role IDs as decimal strings, in ascending string order |
| avatar_hash | ?string | The guild avatar hash, or null when the member has no guild avatar |
| banner_hash | ?string | The guild banner hash, or null when the member has no guild banner |
| bio | ?string | The guild profile bio, or null when none is set |
| pronouns | ?string | The guild profile pronouns, or null when none is set |
| accent_color | ?number | The guild profile accent colour, or null when none is set |
| deaf | boolean | Whether a moderator has deafened the member |
| mute | boolean | Whether a moderator has muted the member |
| communication_disabled_until | ?ISO8601 timestamp | The time the communication restriction expires, or null when the member is not restricted |
| temporary | boolean | Whether the membership is temporary |
Voice move change fields
Section titled “Voice move change fields”Recorded by MEMBER_MOVE and MEMBER_DISCONNECT.
| Field | Type | Description |
|---|---|---|
| channel_id1 | string | The decimal ID of the voice channel the session occupied |
1 A move records the previous channel as old_value and the destination as new_value, while a disconnect records only old_value
Guild ban change fields
Section titled “Guild ban change fields”Recorded by MEMBER_BAN_ADD and MEMBER_BAN_REMOVE.
| Field | Type | Description |
|---|---|---|
| user_id | string | The decimal ID of the banned user |
| moderator_id | string | The decimal ID of the user that issued the ban |
| banned_at | ISO8601 timestamp | The time the ban was issued |
| expires_at | ?ISO8601 timestamp | The expiry of a temporary ban, or null for a permanent ban |
| reason | ?string | The stored ban reason, which is separate from the audit reason |
Guild role change fields
Section titled “Guild role change fields”Recorded by ROLE_CREATE, ROLE_UPDATE, and ROLE_DELETE.
| Field | Type | Description |
|---|---|---|
| role_id | string | The decimal ID of the role itself |
| name | string | The name the role was given by this change (1-100 characters) |
| permissions | string | The decimal permission mask the role grants |
| position | number | The position of the role in the guild hierarchy |
| hoist_position | ?number | The separate hoisting position, or null when the role has none |
| color | number | The colour recorded for the role |
| icon_hash | ?string | The role icon hash, or null when the role has no icon |
| unicode_emoji | ?string | The role Unicode emoji, or null when the role has none |
| hoist | boolean | Whether the role is displayed separately |
| mentionable | boolean | Whether the role is mentionable |
| permissions_diff1 | object | The permission names this change added and removed |
1 Recorded only by Modify guild role, and only when the mask actually changed. The value is an object with added and removed string arrays of permission names
permissions_diff arrives as new_value with no old_value, and the same change list still has the permissions change. The role position and hoist position operations record ROLE_UPDATE without it.
Invite change fields
Section titled “Invite change fields”Recorded by INVITE_CREATE and INVITE_DELETE.
| Field | Type | Description |
|---|---|---|
| code | string | The code that identifies the invite |
| channel_id | ?string | The decimal ID of the channel the invite points at |
| guild_id | ?string | The decimal ID of the guild the invite belongs to |
| inviter_id | ?string | The decimal ID of the user that created the invite |
| uses | number | The use count recorded with the change |
| max_uses | number | The configured maximum use count |
| max_age | number | The configured invite lifetime in seconds |
| temporary | boolean | Whether accepting the invite grants a temporary membership |
| created_at | ISO8601 timestamp | The time the invite was created |
Webhook change fields
Section titled “Webhook change fields”Recorded by WEBHOOK_CREATE, WEBHOOK_UPDATE, and WEBHOOK_DELETE.
| Field | Type | Description |
|---|---|---|
| id | string | The decimal ID of the webhook itself |
| guild_id | ?string | The decimal ID of the guild the webhook belongs to |
| channel_id | ?string | The decimal ID of the channel the webhook posts to |
| name | string | The name the webhook posts under (1-80 characters) |
| creator_id | ?string | The decimal ID of the user that created the webhook |
| avatar_hash | ?string | The webhook avatar hash, or null when no avatar is set |
| type1 | number | The kind of webhook the change recorded |
1 The value is 1 for an incoming webhook and 2 for a channel follower webhook
Emoji change fields
Section titled “Emoji change fields”Recorded by EMOJI_CREATE, EMOJI_UPDATE, and EMOJI_DELETE.
| Field | Type | Description |
|---|---|---|
| emoji_id | string | The decimal ID of the emoji itself |
| name | string | The name the emoji was given by this change (2-32 characters) |
| animated | boolean | Whether the emoji is animated |
| creator_id | string | The decimal ID of the user that created the emoji |
Sticker change fields
Section titled “Sticker change fields”Recorded by STICKER_CREATE, STICKER_UPDATE, and STICKER_DELETE.
| Field | Type | Description |
|---|---|---|
| sticker_id | string | The decimal ID of the sticker itself |
| name | string | The name the sticker was given by this change (2-30 characters) |
| description | ?string | The sticker description, or null when it has none |
| animated | boolean | Whether the sticker is animated |
| creator_id | string | The decimal ID of the user that created the sticker |
Audit log webhook object
Section titled “Audit log webhook object”A reduced webhook object. It omits the execution token, application ID, and creating user, and it names the avatar hash avatar_hash rather than avatar.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the webhook |
| type1 | integer | The kind of webhook this record describes |
| guild_id | ?snowflake | The ID of the guild containing the webhook |
| channel_id | ?snowflake | The ID of the channel the webhook sends messages to |
| name | string | The name the webhook posts under |
| avatar_hash | ?string | The avatar hash of the webhook, or null when no avatar is set |
1 The value is 1 for an incoming webhook and 2 for a channel follower webhook
List guild audit logs
Section titled “List guild audit logs”GET/v1/guilds/{guild_id}/audit-logsReturns one page of guild audit history as a guild audit log response object. Requires VIEW_AUDIT_LOG in the target guild, and no MFA elevation applies.
A guild ID that names no guild returns 404 UNKNOWN_GUILD. A non-member of an existing guild returns 403 MISSING_PERMISSIONS, so guild existence is visible to any authenticated caller.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | The ID of the guild whose audit log is read |
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| limit?1 | integer | The maximum number of entries to return (0-100, default 50) |
| before?2 | snowflake | The cursor selecting entries older than this audit entry ID |
| after?2 | snowflake | The cursor selecting entries newer than this audit entry ID |
| user_id?3 | snowflake | The acting user ID the page is filtered by |
| action_type?3 | integer | The audit action value the page is filtered by |
1 A negative value and a value above 100 are both rejected, and the accepted value 0 is processed as 1
2 The two cursors are mutually exclusive, and supplying both returns 400 INVALID_FORM_BODY with CANNOT_SPECIFY_BOTH_BEFORE_AND_AFTER against before
3 Supplying either filter disables message deletion consolidation for the request, so a page filtered by actor or action returns the unconsolidated entries
The read is ordered from newest to oldest by entry ID. before selects entries below the cursor and after selects entries above it, both read in that same descending order. An after page therefore begins with the newest entry above the cursor.
Consolidation breaks that ordering. A consolidated entry keeps the array position of the first entry of the run it replaces. Its ID is freshly minted and larger than every stored entry on the page, so a client that needs a strictly descending array sorts the page by ID itself.
A page holds fewer entries than limit only when the guild has no further matching entries in that direction.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | guild audit log response object | Page was returned |
| 400 | error response | Both cursors were supplied, or a filter value is invalid |
| 4031 | error response | Guild is unavailable, or VIEW_AUDIT_LOG is absent |
| 404 | error response | Guild does not exist and the request returns UNKNOWN_GUILD |
1 The error code is MISSING_ACCESS for a guild with UNAVAILABLE_FOR_EVERYONE, or UNAVAILABLE_FOR_EVERYONE_BUT_STAFF without the instance staff flag, and MISSING_PERMISSIONS otherwise
Side effects
Section titled “Side effects”Consolidation writes the replacement entry with a fresh snowflake, options.count set to the run length, and no reason. It emits one Guild Audit Log Entry Create Dispatch, which the Gateway delivers only to guild sessions holding VIEW_AUDIT_LOG. A read that finds no run writes nothing and emits no Dispatch.
Rate limit
Section titled “Rate limit”20 requests per 10 seconds for each authenticated user and guild ID, on the guild:audit_logs::guild_id bucket.