diff --git a/Cargo.lock b/Cargo.lock index d56e8d70b..c0dbd6753 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1940,6 +1940,7 @@ dependencies = [ "anyhow", "chrono", "fluxer-svc", + "fluxer_common", "futures", "moka", "rmp-serde", diff --git a/fluxer_admin/build.rs b/fluxer_admin/build.rs index 5f604c26d..c2b2ebca9 100644 --- a/fluxer_admin/build.rs +++ b/fluxer_admin/build.rs @@ -35,8 +35,9 @@ fn generate_admin_api(manifest_dir: &Path, out_dir: &Path) { } let json_str = fs::read_to_string(&spec_path).expect("failed to read openapi-admin.json"); - let spec: openapiv3::OpenAPI = + let mut spec: openapiv3::OpenAPI = serde_json::from_str(&json_str).expect("failed to parse openapi-admin.json"); + adapt_progenitor_throttled_errors(&mut spec); let mut settings = progenitor::GenerationSettings::new(); settings.with_interface(progenitor::InterfaceStyle::Positional); @@ -54,6 +55,87 @@ fn generate_admin_api(manifest_dir: &Path, out_dir: &Path) { fs::write(&output_path, content).expect("failed to write generated API code"); } +fn adapt_progenitor_throttled_errors(spec: &mut openapiv3::OpenAPI) { + let schemas = &spec + .components + .as_ref() + .expect("missing API components") + .schemas; + let error = serde_json::to_value(schemas.get("Error").expect("missing Error schema")) + .expect("failed to inspect Error schema"); + let mut throttled = serde_json::to_value( + schemas + .get("ThrottledError") + .expect("missing ThrottledError schema"), + ) + .expect("failed to inspect ThrottledError schema"); + assert_eq!( + error["additionalProperties"], + serde_json::json!({}), + "Progenitor error adaptation requires Error to retain all additional fields" + ); + let properties = throttled["properties"] + .as_object_mut() + .expect("ThrottledError must be an object schema"); + assert_eq!( + properties + .remove("retry_after") + .expect("missing retry_after")["type"], + "number" + ); + assert_eq!( + properties.remove("global").expect("missing global")["type"], + "boolean" + ); + assert_eq!( + throttled, error, + "ThrottledError must extend the common Error schema" + ); + + for path in spec.paths.paths.values_mut() { + let openapiv3::ReferenceOr::Item(path) = path else { + panic!("Progenitor error adaptation requires inline API paths"); + }; + for operation in [ + &mut path.get, + &mut path.put, + &mut path.post, + &mut path.delete, + &mut path.options, + &mut path.head, + &mut path.patch, + &mut path.trace, + ] + .into_iter() + .flatten() + { + let Some(response) = operation + .responses + .responses + .get_mut(&openapiv3::StatusCode::Code(429)) + else { + continue; + }; + let openapiv3::ReferenceOr::Item(response) = response else { + panic!("Progenitor error adaptation requires inline 429 responses"); + }; + let schema = &mut response + .content + .get_mut("application/json") + .expect("429 responses must return JSON") + .schema; + assert_eq!( + schema, + &Some(openapiv3::ReferenceOr::ref_( + "#/components/schemas/ThrottledError" + )), + "Progenitor only supports one error type per operation" + ); + *schema = Some(openapiv3::ReferenceOr::ref_("#/components/schemas/Error")); + } + } +} + struct Face { css_family: String, weight: u64, diff --git a/fluxer_admin/openapi-admin.json b/fluxer_admin/openapi-admin.json index a04a1f3cc..111cee424 100644 --- a/fluxer_admin/openapi-admin.json +++ b/fluxer_admin/openapi-admin.json @@ -1,5 +1,6 @@ { "openapi": "3.0.3", + "security": [], "info": { "title": "Fluxer API", "version": "1.0.0", @@ -33,7 +34,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -86,7 +87,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -125,11 +126,7 @@ "responses": { "200": { "description": "Success", - "content": { - "application/json": { - "schema": {"type": "array", "items": {"$ref": "#/components/schemas/ListAdminApiKeyResponse"}} - } - } + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdminApiKeyListResponse"}}} }, "400": { "description": "Bad Request - The request was malformed or contained invalid data", @@ -145,7 +142,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -198,7 +195,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -230,7 +227,7 @@ "name": "key_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the key", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the key" } ] @@ -258,7 +255,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -290,12 +287,12 @@ "name": "key_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the key", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the key" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateAdminApiKeyRequest"}}} } }, @@ -322,7 +319,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -354,7 +351,7 @@ "name": "key_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the key", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the key" } ] @@ -384,7 +381,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -416,13 +413,21 @@ "name": "owner_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Restrict the results to the applications owned by this user", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Restrict the results to the applications owned by this user" }, { "name": "guild_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Restrict the results to the applications whose bot users are members of this guild", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Restrict the results to the applications whose bot users are members of this guild" } ] } @@ -451,7 +456,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -483,7 +488,10 @@ "name": "application_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": { + "description": "The ID of the OAuth2 application", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, "description": "The ID of the OAuth2 application" } ] @@ -511,7 +519,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -543,7 +551,10 @@ "name": "application_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": { + "description": "The ID of the OAuth2 application", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, "description": "The ID of the OAuth2 application" } ], @@ -579,7 +590,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -611,31 +622,57 @@ "name": "subject_type", "in": "query", "required": false, - "schema": {"type": "string", "enum": ["user", "guild", "all"], "description": "Type of archives to list"} + "schema": { + "default": "all", + "description": "Type of archives to list", + "x-enumNames": ["user", "guild", "all"], + "x-enumDescriptions": ["List user archives", "List guild archives", "List all archives"], + "enum": ["user", "guild", "all"], + "type": "string" + }, + "description": "Type of archives to list" }, { "name": "subject_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Filter by specific subject ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Filter by specific subject ID" }, { "name": "requested_by", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Filter by user who requested the archive", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Filter by user who requested the archive" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of archives to return (1-200, default 50)"} + "schema": { + "description": "Maximum number of archives to return (1-200, default 50)", + "default": "50", + "type": "string" + }, + "description": "Maximum number of archives to return (1-200, default 50)" }, { "name": "include_expired", "in": "query", "required": false, - "schema": {"type": "string", "description": "Whether to include archives past their expires_at"} + "schema": { + "description": "Whether to include archives past their expires_at", + "default": "false", + "type": "string" + }, + "description": "Whether to include archives past their expires_at" } ] } @@ -664,7 +701,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -696,22 +733,31 @@ "name": "subject_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The subject type" + "schema": { + "description": "The type of subject (user or guild)", + "allOf": [{"$ref": "#/components/schemas/ArchiveSubjectTypeSchema"}] + }, + "description": "The type of subject (user or guild)" }, { "name": "subject_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The subject id" + "schema": { + "description": "The ID of the subject", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the subject" }, { "name": "archive_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The archive id" + "schema": { + "description": "The ID of the archive", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the archive" } ] } @@ -740,7 +786,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -772,22 +818,31 @@ "name": "subject_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The subject type" + "schema": { + "description": "The type of subject (user or guild)", + "allOf": [{"$ref": "#/components/schemas/ArchiveSubjectTypeSchema"}] + }, + "description": "The type of subject (user or guild)" }, { "name": "subject_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The subject id" + "schema": { + "description": "The ID of the subject", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the subject" }, { "name": "archive_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The archive id" + "schema": { + "description": "The ID of the archive", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the archive" } ] } @@ -816,7 +871,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -848,56 +903,77 @@ "name": "q", "in": "query", "required": false, - "schema": {"type": "string", "description": "Free-text query run against the audit log search index"} + "schema": {"description": "Free-text query run against the audit log search index", "type": "string"}, + "description": "Free-text query run against the audit log search index" }, { "name": "admin_user_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Filter by admin user who performed the action", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Filter by admin user who performed the action" }, { "name": "target_type", "in": "query", "required": false, - "schema": {"type": "string", "description": "Filter by target entity type"} + "schema": {"description": "Filter by target entity type", "type": "string"}, + "description": "Filter by target entity type" }, { "name": "target_id", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Filter by target entity ID (user, channel, role, invite code, etc.)" - } + "description": "Filter by target entity ID (user, channel, role, invite code, etc.)", + "type": "string" + }, + "description": "Filter by target entity ID (user, channel, role, invite code, etc.)" }, { "name": "sort_by", "in": "query", "required": false, "schema": { - "type": "string", + "default": "createdAt", + "description": "Field to sort audit logs by", + "x-enumNames": ["createdAt", "relevance"], + "x-enumDescriptions": ["Sort by creation timestamp", "Sort by search relevance score"], "enum": ["createdAt", "relevance"], - "description": "Field to sort audit logs by" - } + "type": "string" + }, + "description": "Field to sort audit logs by" }, { "name": "sort_order", "in": "query", "required": false, - "schema": {"type": "string", "enum": ["asc", "desc"], "description": "Sort order direction"} + "schema": { + "default": "desc", + "description": "Sort order direction", + "x-enumNames": ["asc", "desc"], + "x-enumDescriptions": ["Ascending order (oldest first)", "Descending order (newest first)"], + "enum": ["asc", "desc"], + "type": "string" + }, + "description": "Sort order direction" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of entries to return"} + "schema": {"description": "Maximum number of entries to return", "default": "50", "type": "string"}, + "description": "Maximum number of entries to return" }, { "name": "offset", "in": "query", "required": false, - "schema": {"type": "string", "description": "Number of entries to skip"} + "schema": {"description": "Number of entries to skip", "default": "0", "type": "string"}, + "description": "Number of entries to skip" } ] } @@ -926,7 +1002,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -954,7 +1030,16 @@ "description": "Retrieve a single admin audit log entry by ID, with the same resolved user, guild, and channel summaries the listing returns. Used to inspect one administrative operation during compliance investigations or incident response.", "security": [{"adminApiKey": []}], "parameters": [ - {"name": "log_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "The log id"} + { + "name": "log_id", + "in": "path", + "required": true, + "schema": { + "description": "The ID of the audit log entry", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the audit log entry" + } ] } }, @@ -982,7 +1067,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1037,7 +1122,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1069,33 +1154,39 @@ "name": "list_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The list type" + "schema": { + "description": "The blocklist to operate on", + "allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}] + }, + "description": "The blocklist to operate on" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of entries to return"} + "schema": {"description": "Maximum number of entries to return", "default": "50", "type": "string"}, + "description": "Maximum number of entries to return" }, { "name": "after", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Return entries ordered after this value, taken from the next_after cursor of the previous page" - } + "description": "Return entries ordered after this value, taken from the next_after cursor of the previous page", + "type": "string" + }, + "description": "Return entries ordered after this value, taken from the next_after cursor of the previous page" }, { "name": "scope", "in": "query", "required": false, "schema": { - "enum": ["username", "global_name", "nickname", "bio", "pronouns"], + "description": "Profile field to list. Required on the profile-substring blocklist and rejected on every other blocklist.", "type": "string", - "description": "Profile field to list. Required on the profile-substring blocklist and rejected on every other blocklist." - } + "enum": ["username", "global_name", "nickname", "bio", "pronouns"] + }, + "description": "Profile field to list. Required on the profile-substring blocklist and rejected on every other blocklist." } ] }, @@ -1119,7 +1210,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1151,8 +1242,11 @@ "name": "list_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The list type" + "schema": { + "description": "The blocklist to operate on", + "allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}] + }, + "description": "The blocklist to operate on" } ], "requestBody": { @@ -1183,7 +1277,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1215,8 +1309,11 @@ "name": "list_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The list type" + "schema": { + "description": "The blocklist to operate on", + "allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}] + }, + "description": "The blocklist to operate on" } ], "requestBody": { @@ -1244,7 +1341,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1276,8 +1373,11 @@ "name": "list_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The list type" + "schema": { + "description": "The blocklist to operate on", + "allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}] + }, + "description": "The blocklist to operate on" } ], "requestBody": { @@ -1310,7 +1410,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1342,25 +1442,29 @@ "name": "list_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The list type" + "schema": { + "description": "The blocklist the entry belongs to", + "allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}] + }, + "description": "The blocklist the entry belongs to" }, { "name": "entry_value", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The entry value" + "schema": {"description": "The percent-encoded value of the blocklist entry", "type": "string"}, + "description": "The percent-encoded value of the blocklist entry" }, { "name": "scope", "in": "query", "required": false, "schema": { - "enum": ["username", "global_name", "nickname", "bio", "pronouns"], + "description": "Profile field the entry is scoped to. Required on the profile-substring blocklist and rejected on every other blocklist.", "type": "string", - "description": "Profile field the entry is scoped to. Required on the profile-substring blocklist and rejected on every other blocklist." - } + "enum": ["username", "global_name", "nickname", "bio", "pronouns"] + }, + "description": "Profile field the entry is scoped to. Required on the profile-substring blocklist and rejected on every other blocklist." } ] }, @@ -1384,7 +1488,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1416,15 +1520,18 @@ "name": "list_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The list type" + "schema": { + "description": "The blocklist the entry belongs to", + "allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}] + }, + "description": "The blocklist the entry belongs to" }, { "name": "entry_value", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The entry value" + "schema": {"description": "The percent-encoded value of the blocklist entry", "type": "string"}, + "description": "The percent-encoded value of the blocklist entry" } ], "requestBody": { @@ -1452,7 +1559,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1484,25 +1591,29 @@ "name": "list_type", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The list type" + "schema": { + "description": "The blocklist the entry belongs to", + "allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}] + }, + "description": "The blocklist the entry belongs to" }, { "name": "entry_value", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The entry value" + "schema": {"description": "The percent-encoded value of the blocklist entry", "type": "string"}, + "description": "The percent-encoded value of the blocklist entry" }, { "name": "scope", "in": "query", "required": false, "schema": { - "enum": ["username", "global_name", "nickname", "bio", "pronouns"], + "description": "Profile field the entry is scoped to. Required on the profile-substring blocklist and rejected on every other blocklist.", "type": "string", - "description": "Profile field the entry is scoped to. Required on the profile-substring blocklist and rejected on every other blocklist." - } + "enum": ["username", "global_name", "nickname", "bio", "pronouns"] + }, + "description": "Profile field the entry is scoped to. Required on the profile-substring blocklist and rejected on every other blocklist." } ] } @@ -1531,7 +1642,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1588,7 +1699,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1620,22 +1731,43 @@ "name": "channel_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": { + "description": "The ID of the channel", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, "description": "The ID of the channel" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Number of messages to return (1-100, default 50)"} + "schema": { + "description": "Number of messages to return (1-100, default 50)", + "default": "50", + "type": "string" + }, + "description": "Number of messages to return (1-100, default 50)" }, { "name": "before", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Return messages older than this message ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return messages older than this message ID" }, - {"name": "after", "in": "query", "required": false, "schema": {"$ref": "#/components/schemas/SnowflakeType"}} + { + "name": "after", + "in": "query", + "required": false, + "schema": { + "description": "Return messages newer than this message ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return messages newer than this message ID" + } ] } }, @@ -1663,7 +1795,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1695,14 +1827,20 @@ "name": "channel_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": { + "description": "The ID of the channel", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, "description": "The ID of the channel" }, { "name": "message_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": { + "description": "The ID of the message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, "description": "The ID of the message" }, { @@ -1710,9 +1848,11 @@ "in": "query", "required": false, "schema": { - "type": "string", - "description": "How many messages surrounding the requested message to return as context (1-100, default 50)" - } + "description": "How many messages surrounding the requested message to return as context (1-100, default 50)", + "default": "50", + "type": "string" + }, + "description": "How many messages surrounding the requested message to return as context (1-100, default 50)" } ] }, @@ -1739,7 +1879,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1771,14 +1911,20 @@ "name": "channel_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": { + "description": "The ID of the channel", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, "description": "The ID of the channel" }, { "name": "message_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": { + "description": "The ID of the message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, "description": "The ID of the message" } ] @@ -1794,10 +1940,7 @@ "description": "Success", "content": { "application/json": { - "schema": { - "type": "array", - "items": {"$ref": "#/components/schemas/DiscoveryAdminPendingApplicationResponse"} - } + "schema": {"$ref": "#/components/schemas/DiscoveryAdminPendingApplicationListResponse"} } } }, @@ -1815,7 +1958,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1868,7 +2011,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1900,7 +2043,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ], @@ -1936,7 +2079,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -1974,9 +2117,7 @@ "200": { "description": "Success", "content": { - "application/json": { - "schema": {"type": "array", "items": {"$ref": "#/components/schemas/DiscoveryAdminListedGuildResponse"}} - } + "application/json": {"schema": {"$ref": "#/components/schemas/DiscoveryAdminListedGuildListResponse"}} } }, "400": { @@ -1993,7 +2134,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2025,32 +2166,39 @@ "name": "category_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The category id" + "schema": { + "type": "integer", + "minimum": 0, + "maximum": 8, + "description": "The ID of the discovery category" + }, + "description": "The ID of the discovery category" }, { "name": "limit", "in": "query", "required": false, "schema": { + "default": 50, + "description": "Number of listings to return", "type": "integer", "minimum": 1, - "maximum": 100, - "format": "int32", - "description": "Number of listings to return" - } + "maximum": 100 + }, + "description": "Number of listings to return" }, { "name": "offset", "in": "query", "required": false, "schema": { + "default": 0, + "description": "Pagination offset", "type": "integer", "minimum": 0, - "maximum": 10000, - "format": "int32", - "description": "Pagination offset" - } + "maximum": 10000 + }, + "description": "Pagination offset" } ] } @@ -2064,9 +2212,7 @@ "200": { "description": "Success", "content": { - "application/json": { - "schema": {"type": "array", "items": {"$ref": "#/components/schemas/DiscoveryAdminListedGuildResponse"}} - } + "application/json": {"schema": {"$ref": "#/components/schemas/DiscoveryAdminListedGuildListResponse"}} } }, "400": { @@ -2083,7 +2229,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2136,7 +2282,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2195,7 +2341,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2227,12 +2373,12 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DiscoveryApplicationPatchRequest"}}} } }, @@ -2259,7 +2405,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2291,7 +2437,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ], @@ -2325,7 +2471,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2358,9 +2504,11 @@ "in": "query", "required": false, "schema": { - "type": "string", - "description": "Maximum number of guild processes to return (100-1000, default 100)" - } + "description": "Maximum number of guild processes to return (100-1000, default 100)", + "default": "100", + "type": "string" + }, + "description": "Maximum number of guild processes to return (100-1000, default 100)" } ] } @@ -2389,7 +2537,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2446,7 +2594,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2501,7 +2649,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2554,7 +2702,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2611,7 +2759,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2644,21 +2792,32 @@ "in": "query", "required": false, "schema": { - "type": "string", - "description": "Free-text query matched against the guild name and vanity URL code" - } + "description": "Free-text query matched against the guild name and vanity URL code", + "type": "string" + }, + "description": "Free-text query matched against the guild name and vanity URL code" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum guilds to return (1-200, default 50)"} + "schema": { + "description": "Maximum guilds to return (1-200, default 50)", + "default": "50", + "type": "string" + }, + "description": "Maximum guilds to return (1-200, default 50)" }, { "name": "offset", "in": "query", "required": false, - "schema": {"type": "string", "description": "Guilds to skip before returning results (default 0)"} + "schema": { + "description": "Guilds to skip before returning results (default 0)", + "default": "0", + "type": "string" + }, + "description": "Guilds to skip before returning results (default 0)" } ] } @@ -2687,7 +2846,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2719,7 +2878,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ] @@ -2747,7 +2906,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2779,12 +2938,12 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateGuildRequest"}}} } }, @@ -2811,7 +2970,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2843,7 +3002,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ] @@ -2873,7 +3032,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2905,12 +3064,12 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdminArchiveCreateRequest"}}} } } @@ -2939,7 +3098,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -2971,7 +3130,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ], @@ -3005,7 +3164,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3037,28 +3196,59 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" }, - {"name": "limit", "in": "query", "required": false, "schema": {"$ref": "#/components/schemas/Int32Type"}}, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "description": "Maximum number of audit log entries to return (1-100)", + "maximum": 100, + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "description": "Maximum number of audit log entries to return (1-100)" + }, { "name": "before", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Get entries before this audit log entry ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Get entries before this audit log entry ID" + }, + { + "name": "after", + "in": "query", + "required": false, + "schema": { + "description": "Get entries after this audit log entry ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Get entries after this audit log entry ID" }, - {"name": "after", "in": "query", "required": false, "schema": {"$ref": "#/components/schemas/SnowflakeType"}}, { "name": "user_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Filter entries by the user who performed the action", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Filter entries by the user who performed the action" }, { "name": "action_type", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/AuditLogActionType"} + "schema": { + "description": "Filter entries by the type of action", + "allOf": [{"$ref": "#/components/schemas/AuditLogActionTypeInput"}] + }, + "description": "Filter entries by the type of action" } ] } @@ -3084,7 +3274,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3116,19 +3306,19 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" }, { "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BanGuildMemberBody"}}} } } @@ -3157,7 +3347,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3189,7 +3379,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ] @@ -3219,7 +3409,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3251,20 +3441,30 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum members to return (1-200, default 50)"} + "schema": { + "description": "Maximum members to return (1-200, default 50)", + "default": "50", + "type": "string" + }, + "description": "Maximum members to return (1-200, default 50)" }, { "name": "offset", "in": "query", "required": false, - "schema": {"type": "string", "description": "Members to skip before returning results (default 0)"} + "schema": { + "description": "Members to skip before returning results (default 0)", + "default": "0", + "type": "string" + }, + "description": "Members to skip before returning results (default 0)" } ] } @@ -3293,7 +3493,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3325,14 +3525,14 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" }, { "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -3357,7 +3557,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3389,14 +3589,14 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" }, { "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -3426,7 +3626,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3458,7 +3658,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ] @@ -3488,7 +3688,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3520,7 +3720,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ] @@ -3550,7 +3750,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3582,7 +3782,7 @@ "name": "guild_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the guild", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the guild" } ] @@ -3612,7 +3812,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3663,7 +3863,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3691,7 +3891,7 @@ "description": "Updates instance configuration settings including webhook URLs and SSO parameters. Changes apply immediately. Requires INSTANCE_CONFIG_UPDATE permission.", "security": [{"adminApiKey": []}], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/InstanceConfigUpdateRequest"}}} } } @@ -3720,7 +3920,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3777,7 +3977,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3834,7 +4034,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3866,7 +4066,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -3900,7 +4100,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3928,7 +4128,7 @@ "description": "Creates a one-time-display registration URL that can be sent manually by an administrator. Requires INSTANCE_CONFIG_UPDATE permission.", "security": [{"adminApiKey": []}], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateRegistrationUrlRequest"}}} } } @@ -3957,7 +4157,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -3989,8 +4189,8 @@ "name": "registration_url_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The registration url id" + "schema": {"description": "The ID of the registration URL", "type": "string"}, + "description": "The ID of the registration URL" } ] } @@ -4019,7 +4219,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4051,59 +4251,81 @@ "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of jobs to return (1-200, default 50)"} + "schema": { + "description": "Maximum number of jobs to return (1-200, default 50)", + "default": "50", + "type": "string" + }, + "description": "Maximum number of jobs to return (1-200, default 50)" }, { "name": "cursor_bucket_day", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Day bucket to resume from as a YYYY-MM-DD UTC date, taken from next_cursor.bucket_day" - } + "description": "Day bucket to resume from as a YYYY-MM-DD UTC date, taken from next_cursor.bucket_day", + "type": "string" + }, + "description": "Day bucket to resume from as a YYYY-MM-DD UTC date, taken from next_cursor.bucket_day" }, { "name": "cursor_created_at", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Creation time to resume before as an ISO 8601 timestamp, taken from next_cursor.created_at" - } + "description": "Creation time to resume before as an ISO 8601 timestamp, taken from next_cursor.created_at", + "type": "string" + }, + "description": "Creation time to resume before as an ISO 8601 timestamp, taken from next_cursor.created_at" }, { "name": "cursor_job_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Job to resume from, taken from next_cursor.job_id", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "description": "Job to resume from, taken from next_cursor.job_id" }, { "name": "max_lookback_days", "in": "query", "required": false, - "schema": {"type": "string", "description": "How many day buckets to scan back through (1-60, default 14)"} + "schema": { + "description": "How many day buckets to scan back through (1-60, default 14)", + "default": "14", + "type": "string" + }, + "description": "How many day buckets to scan back through (1-60, default 14)" }, { "name": "status", "in": "query", "required": false, "schema": { - "enum": ["queued", "running", "succeeded", "cancelled", "deadletter"], + "description": "Filter by job status", "type": "string", - "description": "Filter by job status" - } + "enum": ["queued", "running", "succeeded", "cancelled", "deadletter"] + }, + "description": "Filter by job status" }, { "name": "task_type", "in": "query", "required": false, - "schema": {"type": "string", "description": "Filter by task type"} + "schema": {"description": "Filter by task type", "type": "string"}, + "description": "Filter by task type" }, { "name": "requested_by_user_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Filter by admin user who scheduled the job", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Filter by admin user who scheduled the job" } ] } @@ -4132,7 +4354,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4185,7 +4407,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4213,7 +4435,13 @@ "description": "Fetch a single job ledger entry with full payload, result, and progress.", "security": [{"adminApiKey": []}], "parameters": [ - {"name": "job_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "The job id"} + { + "name": "job_id", + "in": "path", + "required": true, + "schema": {"description": "The ID of the job", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, + "description": "The ID of the job" + } ] } }, @@ -4241,7 +4469,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4269,7 +4497,13 @@ "description": "Mark a job as cancel-requested. The handler must be cooperatively cancellable — it will see the flag at its next `helpers.shouldCancel()` check. Returns `{cancelled: false}` for already-terminal jobs.", "security": [{"adminApiKey": []}], "parameters": [ - {"name": "job_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "The job id"} + { + "name": "job_id", + "in": "path", + "required": true, + "schema": {"description": "The ID of the job", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, + "description": "The ID of the job" + } ] } }, @@ -4297,7 +4531,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4348,7 +4582,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4405,7 +4639,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4437,49 +4671,72 @@ "name": "channel_id", "in": "query", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Return messages sent in this channel", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return messages sent in this channel" }, { "name": "q", "in": "query", "required": false, - "schema": {"type": "string", "description": "Free-text query matched against message content"} + "schema": {"description": "Free-text query matched against message content", "type": "string"}, + "description": "Free-text query matched against message content" }, { "name": "message_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Return the single message with this ID together with its surrounding context; ignores every other filter", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return the single message with this ID together with its surrounding context; ignores every other filter" }, { "name": "attachment_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Return the single message carrying this attachment together with its surrounding context; requires filename", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return the single message carrying this attachment together with its surrounding context; requires filename" }, { "name": "filename", "in": "query", "required": false, - "schema": {"type": "string", "description": "The filename of the attachment named by attachment_id"} + "schema": { + "description": "The filename of the attachment named by attachment_id", + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "description": "The filename of the attachment named by attachment_id" }, { "name": "context_limit", "in": "query", "required": false, "schema": { - "type": "string", - "description": "How many messages surrounding a message resolved by message_id or attachment_id to return as context (1-100, default 50)" - } + "description": "How many messages surrounding a message resolved by message_id or attachment_id to return as context (1-100, default 50)", + "default": "50", + "type": "string" + }, + "description": "How many messages surrounding a message resolved by message_id or attachment_id to return as context (1-100, default 50)" }, { "name": "limit", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Maximum number of messages to return when searching (1-100, default 25)" - } + "description": "Maximum number of messages to return when searching (1-100, default 25)", + "default": "25", + "type": "string" + }, + "description": "Maximum number of messages to return when searching (1-100, default 25)" } ] } @@ -4510,7 +4767,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4567,7 +4824,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4595,7 +4852,16 @@ "description": "Returns the progress of a queued message shred job, including whether it is complete. Requires MESSAGE_SHRED permission.", "security": [{"adminApiKey": []}], "parameters": [ - {"name": "job_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "The job id"} + { + "name": "job_id", + "in": "path", + "required": true, + "schema": { + "description": "The ID of the message shred job", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the message shred job" + } ] } }, @@ -4623,7 +4889,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4655,97 +4921,158 @@ "name": "q", "in": "query", "required": false, - "schema": {"type": "string", "description": "Free-text query matched against the searchable report fields"} + "schema": {"description": "Free-text query matched against the searchable report fields", "type": "string"}, + "description": "Free-text query matched against the searchable report fields" }, { "name": "status", "in": "query", "required": false, "schema": { - "type": "string", + "description": "Only return reports with this status", + "x-enumNames": ["pending", "resolved"], + "x-enumDescriptions": [ + "Only reports that are waiting to be reviewed", + "Only reports that have been resolved" + ], "enum": ["pending", "resolved"], - "description": "Only return reports with this status" - } + "type": "string" + }, + "description": "Only return reports with this status" }, { "name": "report_type", "in": "query", "required": false, "schema": { - "type": "string", + "description": "Only return reports about this kind of entity", + "x-enumNames": ["message", "user", "guild"], + "x-enumDescriptions": [ + "Only reports about a message", + "Only reports about a user", + "Only reports about a community" + ], "enum": ["message", "user", "guild"], - "description": "Only return reports about this kind of entity" - } + "type": "string" + }, + "description": "Only return reports about this kind of entity" }, { "name": "category", "in": "query", "required": false, - "schema": {"type": "string", "description": "Only return reports filed under this category"} + "schema": {"description": "Only return reports filed under this category", "type": "string"}, + "description": "Only return reports filed under this category" }, { "name": "reporter_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Only return reports submitted by this user", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Only return reports submitted by this user" }, { "name": "reported_user_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Only return reports about this user", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Only return reports about this user" }, { "name": "reported_guild_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Only return reports about this community", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Only return reports about this community" }, { "name": "reported_channel_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Only return reports about content in this channel", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Only return reports about content in this channel" }, { "name": "guild_context_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Only return reports filed from within this community", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Only return reports filed from within this community" }, { "name": "resolved_by_admin_id", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Only return reports resolved by this admin", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Only return reports resolved by this admin" }, { "name": "sort_by", "in": "query", "required": false, "schema": { - "type": "string", + "default": "reported_at", + "description": "The field to sort the reports by", + "x-enumNames": ["created_at", "reported_at", "resolved_at"], + "x-enumDescriptions": [ + "Sort by the time the report was created", + "Sort by the time the report was submitted", + "Sort by the time the report was resolved" + ], "enum": ["created_at", "reported_at", "resolved_at"], - "description": "The field to sort the reports by" - } + "type": "string" + }, + "description": "The field to sort the reports by" }, { "name": "sort_order", "in": "query", "required": false, - "schema": {"type": "string", "enum": ["asc", "desc"], "description": "The direction to sort the reports in"} + "schema": { + "default": "desc", + "description": "The direction to sort the reports in", + "x-enumNames": ["asc", "desc"], + "x-enumDescriptions": ["Ascending order (oldest first)", "Descending order (newest first)"], + "enum": ["asc", "desc"], + "type": "string" + }, + "description": "The direction to sort the reports in" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of reports to return (1-200, default 50)"} + "schema": { + "description": "Maximum number of reports to return (1-200, default 50)", + "default": "50", + "type": "string" + }, + "description": "Maximum number of reports to return (1-200, default 50)" }, { "name": "offset", "in": "query", "required": false, - "schema": {"type": "string", "description": "Number of reports to skip"} + "schema": {"description": "Number of reports to skip", "default": "0", "type": "string"}, + "description": "Number of reports to skip" } ] } @@ -4774,7 +5101,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4806,8 +5133,11 @@ "name": "report_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The report id" + "schema": { + "description": "The ID of the report", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the report" } ] }, @@ -4834,7 +5164,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4866,8 +5196,11 @@ "name": "report_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The report id" + "schema": { + "description": "The ID of the report", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the report" } ], "requestBody": { @@ -4900,7 +5233,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4928,7 +5261,13 @@ "description": "Reads the progress of a queued search index refresh. Returns the completion counts and current phase, or a not_found status once the record has expired. Requires GUILD_LOOKUP permission.", "security": [{"adminApiKey": []}], "parameters": [ - {"name": "job_id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "The job id"} + { + "name": "job_id", + "in": "path", + "required": true, + "schema": {"description": "ID of the index refresh to read", "type": "string"}, + "description": "ID of the index refresh to read" + } ] } }, @@ -4956,7 +5295,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -4988,12 +5327,45 @@ "name": "index_name", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The index name" + "schema": { + "description": "The name of the search index", + "x-enumNames": [ + "guilds", + "users", + "reports", + "audit_logs", + "channel_messages", + "guild_members", + "favorite_memes", + "discovery" + ], + "x-enumDescriptions": [ + "Guild search index", + "User search index", + "Report search index", + "Audit log search index", + "Channel message search index", + "Guild member search index", + "Favourite meme search index", + "Discovery guild search index" + ], + "enum": [ + "guilds", + "users", + "reports", + "audit_logs", + "channel_messages", + "guild_members", + "favorite_memes", + "discovery" + ], + "type": "string" + }, + "description": "The name of the search index" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RefreshSearchIndexRequest"}}} } } @@ -5022,7 +5394,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5063,7 +5435,7 @@ "responses": { "200": { "description": "Success", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HeapSnapshotResponse"}}} + "content": {"application/octet-stream": {"schema": {"$ref": "#/components/schemas/HeapSnapshotResponse"}}} }, "400": { "description": "Bad Request - The request was malformed or contained invalid data", @@ -5079,7 +5451,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5132,7 +5504,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5165,60 +5537,71 @@ "in": "query", "required": false, "schema": { - "type": "string", - "description": "Restrict the results to the users matching this free-text query" - } + "description": "Restrict the results to the users matching this free-text query", + "type": "string" + }, + "description": "Restrict the results to the users matching this free-text query" }, { "name": "user_id", "in": "query", "required": false, "schema": { - "oneOf": [ - {"$ref": "#/components/schemas/SnowflakeType"}, - {"type": "array", "items": {"$ref": "#/components/schemas/SnowflakeType"}, "maxItems": 100} - ], - "description": "Restrict the results to these users. Repeat the parameter to pass more than one." - } + "description": "Restrict the results to these users. Repeat the parameter to pass more than one.", + "anyOf": [ + {"$ref": "#/components/schemas/SnowflakeStringType"}, + {"maxItems": 100, "type": "array", "items": {"$ref": "#/components/schemas/SnowflakeStringType"}} + ] + }, + "description": "Restrict the results to these users. Repeat the parameter to pass more than one." }, { "name": "resolve", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Resolve one exact identifier: a username#discriminator tag, a user ID, an email address, or a Stripe subscription ID" - } + "description": "Resolve one exact identifier: a username#discriminator tag, a user ID, an email address, or a Stripe subscription ID", + "type": "string" + }, + "description": "Resolve one exact identifier: a username#discriminator tag, a user ID, an email address, or a Stripe subscription ID" }, { "name": "email", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Restrict the results to the user with this exact email address" - } + "description": "Restrict the results to the user with this exact email address", + "type": "string" + }, + "description": "Restrict the results to the user with this exact email address" }, { "name": "last_active_ip", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Restrict the results to the users whose last active IP address matches this one exactly" - } + "description": "Restrict the results to the users whose last active IP address matches this one exactly", + "type": "string" + }, + "description": "Restrict the results to the users whose last active IP address matches this one exactly" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of users to return"} + "schema": {"description": "Maximum number of users to return", "default": "50", "type": "string"}, + "description": "Maximum number of users to return" }, { "name": "offset", "in": "query", "required": false, - "schema": {"type": "string", "description": "Number of users to skip before returning results"} + "schema": { + "description": "Number of users to skip before returning results", + "default": "0", + "type": "string" + }, + "description": "Number of users to skip before returning results" } ] } @@ -5247,7 +5630,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5300,7 +5683,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5332,7 +5715,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -5362,7 +5745,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5394,7 +5777,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -5428,7 +5811,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5460,7 +5843,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -5490,7 +5873,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5522,12 +5905,12 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdminArchiveCreateRequest"}}} } } @@ -5556,7 +5939,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5588,12 +5971,12 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BanUserAvatarRequest"}}} } } @@ -5622,7 +6005,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5654,7 +6037,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -5686,7 +6069,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5718,7 +6101,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -5748,7 +6131,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5780,7 +6163,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -5816,7 +6199,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5848,20 +6231,22 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" }, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of entries to return"} + "schema": {"description": "Maximum number of entries to return", "default": "50", "type": "string"}, + "description": "Maximum number of entries to return" }, { "name": "page_token", "in": "query", "required": false, - "schema": {"type": "string", "description": "Pagination token for the next page of results"} + "schema": {"description": "Pagination token for the next page of results", "type": "string"}, + "description": "Pagination token for the next page of results" } ] } @@ -5890,7 +6275,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5922,7 +6307,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -5956,7 +6341,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -5988,7 +6373,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -6020,7 +6405,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6052,7 +6437,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -6082,7 +6467,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6114,27 +6499,46 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" }, { "name": "type", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/AdminUserDmChannelType"} + "schema": { + "default": "dm", + "description": "The kind of direct message channel to list. Defaults to the one-to-one direct message channels.", + "allOf": [{"$ref": "#/components/schemas/AdminUserDmChannelType"}] + }, + "description": "The kind of direct message channel to list. Defaults to the one-to-one direct message channels." }, { "name": "before", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Return channels with IDs lower than this channel ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return channels with IDs lower than this channel ID" + }, + { + "name": "after", + "in": "query", + "required": false, + "schema": { + "description": "Return channels with IDs higher than this channel ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return channels with IDs higher than this channel ID" }, - {"name": "after", "in": "query", "required": false, "schema": {"$ref": "#/components/schemas/SnowflakeType"}}, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of DM channels to return"} + "schema": {"description": "Maximum number of DM channels to return", "default": "50", "type": "string"}, + "description": "Maximum number of DM channels to return" } ] } @@ -6163,7 +6567,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6195,7 +6599,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -6229,7 +6633,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6261,7 +6665,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -6291,7 +6695,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6323,12 +6727,12 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], "requestBody": { - "required": true, + "required": false, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdminUserFlagsUpdateRequest"}}} } } @@ -6357,7 +6761,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6389,30 +6793,46 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" }, { "name": "before", "in": "query", "required": false, - "schema": {"$ref": "#/components/schemas/SnowflakeType"} + "schema": { + "description": "Return guilds with IDs lower than this guild ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return guilds with IDs lower than this guild ID" + }, + { + "name": "after", + "in": "query", + "required": false, + "schema": { + "description": "Return guilds with IDs higher than this guild ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "Return guilds with IDs higher than this guild ID" }, - {"name": "after", "in": "query", "required": false, "schema": {"$ref": "#/components/schemas/SnowflakeType"}}, { "name": "limit", "in": "query", "required": false, - "schema": {"type": "string", "description": "Maximum number of guilds to return"} + "schema": {"description": "Maximum number of guilds to return", "default": "200", "type": "string"}, + "description": "Maximum number of guilds to return" }, { "name": "with_counts", "in": "query", "required": false, "schema": { - "type": "string", - "description": "Whether to resolve live member and presence counts from the gateway" - } + "description": "Whether to resolve live member and presence counts from the gateway", + "default": "false", + "type": "string" + }, + "description": "Whether to resolve live member and presence counts from the gateway" } ] } @@ -6441,7 +6861,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6473,7 +6893,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -6503,7 +6923,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6535,7 +6955,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -6569,7 +6989,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6601,7 +7021,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" }, { @@ -6609,9 +7029,11 @@ "in": "query", "required": false, "schema": { - "type": "string", - "description": "Count the messages that would be deleted without deleting anything (default true)" - } + "description": "Count the messages that would be deleted without deleting anything (default true)", + "default": "true", + "type": "string" + }, + "description": "Count the messages that would be deleted without deleting anything (default true)" } ] } @@ -6637,7 +7059,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6669,7 +7091,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -6696,7 +7118,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6728,7 +7150,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -6758,7 +7180,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6790,7 +7212,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -6826,7 +7248,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6858,12 +7280,12 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], "requestBody": { - "required": true, + "required": false, "content": { "application/json": {"schema": {"$ref": "#/components/schemas/AdminUserPremiumFlagsUpdateRequest"}} } @@ -6894,7 +7316,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6926,7 +7348,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -6960,7 +7382,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -6992,7 +7414,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -7022,7 +7444,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7054,7 +7476,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" }, { @@ -7062,10 +7484,10 @@ "in": "query", "required": true, "schema": { - "enum": ["friend", "incoming_request", "outgoing_request", "blocked"], - "type": "string", - "description": "Category of relationships the operation applies to" - } + "description": "Category of relationships the operation applies to", + "allOf": [{"$ref": "#/components/schemas/RelationshipCategoryEnum"}] + }, + "description": "Category of relationships the operation applies to" } ] } @@ -7091,7 +7513,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7123,25 +7545,28 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" }, { "name": "target_user_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The target user id" + "schema": { + "description": "The ID of the target user", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "description": "The ID of the target user" }, { "name": "category", "in": "query", "required": true, "schema": { - "enum": ["friend", "incoming_request", "outgoing_request", "blocked"], - "type": "string", - "description": "Category of relationships the operation applies to" - } + "description": "Category of relationships the operation applies to", + "allOf": [{"$ref": "#/components/schemas/RelationshipCategoryEnum"}] + }, + "description": "Category of relationships the operation applies to" } ] } @@ -7170,7 +7595,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7202,7 +7627,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -7230,7 +7655,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7262,7 +7687,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -7292,7 +7717,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7324,7 +7749,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -7360,7 +7785,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7392,7 +7817,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -7428,7 +7853,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7460,7 +7885,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -7494,7 +7919,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7526,7 +7951,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -7560,7 +7985,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7592,7 +8017,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ], @@ -7623,7 +8048,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7655,7 +8080,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -7685,7 +8110,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7717,7 +8142,7 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" } ] @@ -7744,7 +8169,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7776,15 +8201,15 @@ "name": "user_id", "in": "path", "required": true, - "schema": {"$ref": "#/components/schemas/SnowflakeType"}, + "schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, "description": "The ID of the user" }, { "name": "credential_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The credential id" + "schema": {"description": "The ID of the WebAuthn credential", "type": "string"}, + "description": "The ID of the WebAuthn credential" } ] } @@ -7813,7 +8238,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7845,7 +8270,12 @@ "name": "include_servers", "in": "query", "required": false, - "schema": {"type": "string", "description": "Whether to include voice servers in the response"} + "schema": { + "description": "Whether to include voice servers in the response", + "default": "false", + "type": "string" + }, + "description": "Whether to include voice servers in the response" } ] }, @@ -7872,7 +8302,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7929,7 +8359,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -7961,14 +8391,19 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the voice region", "type": "string"}, + "description": "ID of the voice region" }, { "name": "include_servers", "in": "query", "required": false, - "schema": {"type": "string", "description": "Whether to include voice servers in the response"} + "schema": { + "description": "Whether to include voice servers in the response", + "default": "false", + "type": "string" + }, + "description": "Whether to include voice servers in the response" } ] }, @@ -7995,7 +8430,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -8027,13 +8462,13 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the voice region", "type": "string"}, + "description": "ID of the voice region" } ], "requestBody": { - "required": true, - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateVoiceRegionRequest"}}} + "required": false, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateVoiceRegionRequestBody"}}} } }, "delete": { @@ -8059,7 +8494,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -8091,8 +8526,8 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the voice region", "type": "string"}, + "description": "ID of the voice region" } ] } @@ -8121,7 +8556,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -8153,8 +8588,8 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the voice region", "type": "string"}, + "description": "ID of the voice region" } ] }, @@ -8181,7 +8616,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -8213,13 +8648,13 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the voice region", "type": "string"}, + "description": "ID of the voice region" } ], "requestBody": { "required": true, - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateVoiceServerRequest"}}} + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateVoiceServerRequestBody"}}} } } }, @@ -8247,7 +8682,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -8279,15 +8714,15 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the region the server belongs to", "type": "string"}, + "description": "ID of the region the server belongs to" }, { "name": "server_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The server id" + "schema": {"description": "ID of the voice server", "type": "string"}, + "description": "ID of the voice server" } ] }, @@ -8314,7 +8749,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -8346,20 +8781,20 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the region the server belongs to", "type": "string"}, + "description": "ID of the region the server belongs to" }, { "name": "server_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The server id" + "schema": {"description": "ID of the voice server", "type": "string"}, + "description": "ID of the voice server" } ], "requestBody": { - "required": true, - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateVoiceServerRequest"}}} + "required": false, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateVoiceServerRequestBody"}}} } }, "delete": { @@ -8385,7 +8820,7 @@ }, "429": { "description": "Too Many Requests - You are being rate limited", - "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, + "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}}, "headers": { "Retry-After": { "description": "Number of seconds to wait before retrying (only on 429)", @@ -8417,15 +8852,15 @@ "name": "region_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The region id" + "schema": {"description": "ID of the region the server belongs to", "type": "string"}, + "description": "ID of the region the server belongs to" }, { "name": "server_id", "in": "path", "required": true, - "schema": {"type": "string"}, - "description": "The server id" + "schema": {"description": "ID of the voice server", "type": "string"}, + "description": "ID of the voice server" } ] } @@ -8433,309 +8868,3887 @@ }, "components": { "schemas": { - "AdminAclListResponse": { + "Error": { + "type": "object", + "properties": { + "code": {"type": "string", "description": "Machine-readable error code"}, + "message": {"type": "string", "description": "Human-readable error message"}, + "errors": { + "description": "Field-specific validation errors", + "type": "array", + "items": { + "type": "object", + "properties": { + "path": {"type": "string", "description": "Field path that failed validation"}, + "code": {"description": "Machine-readable validation error code", "type": "string"}, + "message": {"type": "string", "description": "Human-readable validation error message"} + }, + "required": ["path", "message"], + "additionalProperties": false + } + } + }, + "required": ["code", "message"], + "additionalProperties": {} + }, + "ThrottledError": { + "type": "object", + "properties": { + "code": {"type": "string", "description": "Machine-readable error code"}, + "message": {"type": "string", "description": "Human-readable error message"}, + "errors": { + "description": "Field-specific validation errors", + "type": "array", + "items": { + "type": "object", + "properties": { + "path": {"type": "string", "description": "Field path that failed validation"}, + "code": {"description": "Machine-readable validation error code", "type": "string"}, + "message": {"type": "string", "description": "Human-readable validation error message"} + }, + "required": ["path", "message"], + "additionalProperties": false + } + }, + "retry_after": {"type": "number", "description": "Seconds to wait before retrying"}, + "global": {"type": "boolean", "description": "Whether this is a global rate limit"} + }, + "required": ["code", "message"], + "additionalProperties": {} + }, + "DeleteVoiceResponse": { + "type": "object", + "properties": {"success": {"type": "boolean", "description": "Whether the deletion was successful"}}, + "required": ["success"], + "additionalProperties": false + }, + "UpdateVoiceServerRequestBody": { + "type": "object", + "properties": { + "endpoint": { + "description": "Client signal WebSocket endpoint URL for the voice server", + "type": "string", + "format": "uri" + }, + "api_key": {"description": "API key for authenticating with the voice server", "type": "string"}, + "api_secret": {"description": "API secret for authenticating with the voice server", "type": "string"}, + "latitude": { + "description": "Optional geographic latitude override for this server", + "nullable": true, + "type": "number" + }, + "longitude": { + "description": "Optional geographic longitude override for this server", + "nullable": true, + "type": "number" + }, + "is_active": {"description": "Whether the server is currently active", "type": "boolean"}, + "soft_connection_limit": { + "description": "Connection count above which placement prefers another server, or null for no limit", + "nullable": true, + "type": "integer", + "minimum": 1, + "maximum": 2147483647 + }, + "vip_only": {"description": "Whether this server is restricted to VIP users", "type": "boolean"}, + "required_guild_features": { + "description": "Guild features required to use this server", + "maxItems": 100, + "type": "array", + "items": {"type": "string"} + }, + "allowed_guild_ids": { + "description": "Guild IDs explicitly allowed to use this server", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + }, + "allowed_user_ids": { + "description": "User IDs explicitly allowed to use this server", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + } + } + }, + "UpdateVoiceServerResponse": { + "type": "object", + "properties": { + "server": { + "description": "Updated voice server", + "allOf": [{"$ref": "#/components/schemas/VoiceServerAdminResponse"}] + } + }, + "required": ["server"], + "additionalProperties": false + }, + "GetVoiceServerResponse": { + "type": "object", + "properties": { + "server": { + "nullable": true, + "description": "Voice server details or null if not found", + "allOf": [{"$ref": "#/components/schemas/VoiceServerAdminResponse"}] + } + }, + "required": ["server"], + "additionalProperties": false + }, + "CreateVoiceServerRequestBody": { + "type": "object", + "properties": { + "server_id": {"description": "Unique identifier for the voice server", "type": "string"}, + "endpoint": { + "type": "string", + "format": "uri", + "description": "Client signal WebSocket endpoint URL for the voice server" + }, + "api_key": {"description": "API key for authenticating with the voice server", "type": "string"}, + "api_secret": {"description": "API secret for authenticating with the voice server", "type": "string"}, + "latitude": { + "description": "Optional geographic latitude override for this server", + "nullable": true, + "type": "number" + }, + "longitude": { + "description": "Optional geographic longitude override for this server", + "nullable": true, + "type": "number" + }, + "is_active": {"default": true, "description": "Whether the server is currently active", "type": "boolean"}, + "soft_connection_limit": { + "default": null, + "description": "Connection count above which placement prefers another server, or null for no limit", + "nullable": true, + "type": "integer", + "minimum": 1, + "maximum": 2147483647 + }, + "vip_only": { + "default": false, + "description": "Whether this server is restricted to VIP users", + "type": "boolean" + }, + "required_guild_features": { + "default": [], + "description": "Guild features required to use this server", + "maxItems": 100, + "type": "array", + "items": {"type": "string"} + }, + "allowed_guild_ids": { + "description": "Guild IDs explicitly allowed to use this server", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + }, + "allowed_user_ids": { + "description": "User IDs explicitly allowed to use this server", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + } + }, + "required": ["server_id", "endpoint", "api_key", "api_secret"] + }, + "CreateVoiceServerResponse": { + "type": "object", + "properties": { + "server": { + "description": "Created voice server", + "allOf": [{"$ref": "#/components/schemas/VoiceServerAdminResponse"}] + } + }, + "required": ["server"], + "additionalProperties": false + }, + "ListVoiceServersResponse": { + "type": "object", + "properties": { + "servers": { + "type": "array", + "items": {"$ref": "#/components/schemas/VoiceServerAdminResponse"}, + "description": "List of voice servers" + } + }, + "required": ["servers"], + "additionalProperties": false + }, + "UpdateVoiceRegionRequestBody": { + "type": "object", + "properties": { + "name": {"description": "Display name of the voice region", "type": "string"}, + "emoji": {"description": "Emoji representing the region", "type": "string"}, + "latitude": {"description": "Geographic latitude coordinate", "type": "number"}, + "longitude": {"description": "Geographic longitude coordinate", "type": "number"}, + "is_default": {"description": "Whether this is the default region", "type": "boolean"}, + "vip_only": {"description": "Whether this region is restricted to VIP users", "type": "boolean"}, + "required_guild_features": { + "description": "Guild features required to use this region", + "maxItems": 100, + "type": "array", + "items": {"type": "string"} + }, + "allowed_guild_ids": { + "description": "Guild IDs explicitly allowed to use this region", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + }, + "allowed_user_ids": { + "description": "User IDs explicitly allowed to use this region", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + } + } + }, + "UpdateVoiceRegionResponse": { + "type": "object", + "properties": { + "region": { + "description": "Updated voice region", + "allOf": [{"$ref": "#/components/schemas/VoiceRegionAdminResponse"}] + } + }, + "required": ["region"], + "additionalProperties": false + }, + "GetVoiceRegionResponse": { + "type": "object", + "properties": { + "region": { + "nullable": true, + "description": "Voice region details or null if not found", + "type": "object", + "properties": { + "id": {"type": "string", "description": "Unique identifier for the voice region"}, + "name": {"type": "string", "description": "Display name of the voice region"}, + "emoji": {"type": "string", "description": "Emoji representing the region"}, + "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, + "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, + "is_default": {"type": "boolean", "description": "Whether this is the default region"}, + "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, + "required_guild_features": { + "maxItems": 100, + "type": "array", + "items": {"type": "string"}, + "description": "Guild features required to use this region" + }, + "allowed_guild_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "description": "Guild IDs explicitly allowed to use this region" + }, + "allowed_user_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "description": "User IDs explicitly allowed to use this region" + }, + "created_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the region was created", + "type": "string" + }, + "updated_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the region was last updated", + "type": "string" + }, + "servers": { + "description": "Voice servers in this region", + "type": "array", + "items": {"$ref": "#/components/schemas/VoiceServerAdminResponse"} + } + }, + "required": [ + "id", + "name", + "emoji", + "latitude", + "longitude", + "is_default", + "vip_only", + "required_guild_features", + "allowed_guild_ids", + "allowed_user_ids", + "created_at", + "updated_at" + ], + "additionalProperties": false + } + }, + "required": ["region"], + "additionalProperties": false + }, + "CreateVoiceRegionRequest": { + "type": "object", + "properties": { + "id": {"description": "Unique identifier for the voice region", "type": "string"}, + "name": {"description": "Display name of the voice region", "type": "string"}, + "emoji": {"description": "Emoji representing the region", "type": "string"}, + "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, + "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, + "is_default": {"default": false, "description": "Whether this is the default region", "type": "boolean"}, + "vip_only": { + "default": false, + "description": "Whether this region is restricted to VIP users", + "type": "boolean" + }, + "required_guild_features": { + "default": [], + "description": "Guild features required to use this region", + "maxItems": 100, + "type": "array", + "items": {"type": "string"} + }, + "allowed_guild_ids": { + "description": "Guild IDs explicitly allowed to use this region", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + }, + "allowed_user_ids": { + "description": "User IDs explicitly allowed to use this region", + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"} + } + }, + "required": ["id", "name", "emoji", "latitude", "longitude"] + }, + "CreateVoiceRegionResponse": { + "type": "object", + "properties": { + "region": { + "description": "Created voice region", + "allOf": [{"$ref": "#/components/schemas/VoiceRegionAdminResponse"}] + } + }, + "required": ["region"], + "additionalProperties": false + }, + "ListVoiceRegionsResponse": { + "type": "object", + "properties": { + "regions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"type": "string", "description": "Unique identifier for the voice region"}, + "name": {"type": "string", "description": "Display name of the voice region"}, + "emoji": {"type": "string", "description": "Emoji representing the region"}, + "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, + "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, + "is_default": {"type": "boolean", "description": "Whether this is the default region"}, + "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, + "required_guild_features": { + "maxItems": 100, + "type": "array", + "items": {"type": "string"}, + "description": "Guild features required to use this region" + }, + "allowed_guild_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "description": "Guild IDs explicitly allowed to use this region" + }, + "allowed_user_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "description": "User IDs explicitly allowed to use this region" + }, + "created_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the region was created", + "type": "string" + }, + "updated_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the region was last updated", + "type": "string" + }, + "servers": { + "description": "Voice servers in this region", + "type": "array", + "items": {"$ref": "#/components/schemas/VoiceServerAdminResponse"} + } + }, + "required": [ + "id", + "name", + "emoji", + "latitude", + "longitude", + "is_default", + "vip_only", + "required_guild_features", + "allowed_guild_ids", + "allowed_user_ids", + "created_at", + "updated_at" + ], + "additionalProperties": false + }, + "description": "List of voice regions" + } + }, + "required": ["regions"], + "additionalProperties": false + }, + "SnowflakeType": { + "anyOf": [{"type": "string"}, {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991}], + "format": "snowflake" + }, + "WebAuthnCredentialListResponse": { + "type": "array", + "items": {"$ref": "#/components/schemas/WebAuthnCredentialResponse"} + }, + "AdminUserUsernameUpdateRequest": { + "type": "object", + "properties": { + "username": { + "description": "New username for the user", + "allOf": [{"$ref": "#/components/schemas/UsernameType"}] + }, + "discriminator": { + "description": "Legacy discriminator value", + "allOf": [{"$ref": "#/components/schemas/DiscriminatorType"}] + } + }, + "required": ["username"] + }, + "UserMutationResponse": { + "type": "object", + "properties": {"user": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}, + "required": ["user"], + "additionalProperties": false + }, + "AdminUserTraitsRequest": { + "type": "object", + "properties": { + "traits": { + "maxItems": 100, + "type": "array", + "items": {"type": "string"}, + "description": "List of traits to assign to the user" + } + }, + "required": ["traits"] + }, + "AdminUserSystemStatusRequest": { + "type": "object", + "properties": { + "system": {"type": "boolean", "description": "Whether the user should be marked as a system user"} + }, + "required": ["system"] + }, + "AdminUserSuspiciousActivityFlagsRequest": { + "type": "object", + "properties": { + "flags": { + "description": "Bitmask of suspicious activity flags", + "allOf": [{"$ref": "#/components/schemas/SuspiciousActivityFlags"}] + } + }, + "required": ["flags"] + }, + "AdminUserSuspiciousDisableRequest": { + "type": "object", + "properties": { + "flags": { + "description": "Bitmask of suspicious activity flags that triggered the disable", + "allOf": [{"$ref": "#/components/schemas/SuspiciousActivityFlags"}] + } + }, + "required": ["flags"] + }, + "TerminateSessionsResponse": { + "type": "object", + "properties": {"terminated_count": {"$ref": "#/components/schemas/Int32Type"}}, + "required": ["terminated_count"], + "additionalProperties": false + }, + "ListUserSessionsResponse": { + "type": "object", + "properties": { + "sessions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "session_id_hash": { + "description": "Hashed session identifier (base64url)", + "type": "string", + "minLength": 8, + "maxLength": 256 + }, + "created_at": {"type": "string", "description": "ISO timestamp when the session was created"}, + "approx_last_used_at": { + "type": "string", + "description": "ISO timestamp of the session last usage (approximate)" + }, + "client_ip": {"description": "Client IP address", "type": "string", "minLength": 1, "maxLength": 64}, + "client_ip_reverse": { + "nullable": true, + "description": "Reverse DNS hostname for the client IP (PTR), if available", + "type": "string" + }, + "client_os": { + "nullable": true, + "description": "Client operating system, if detected", + "type": "string" + }, + "client_platform": {"nullable": true, "description": "Client platform, if detected", "type": "string"}, + "client_location": { + "nullable": true, + "description": "Approximate geo location label for the client IP, if available", + "type": "string" + }, + "deleted_at": { + "nullable": true, + "description": "ISO timestamp when the session was terminated, or null if still active", + "type": "string" + } + }, + "required": [ + "session_id_hash", + "created_at", + "approx_last_used_at", + "client_ip", + "client_ip_reverse", + "client_os", + "client_platform", + "client_location", + "deleted_at" + ], + "additionalProperties": false + } + } + }, + "required": ["sessions"], + "additionalProperties": false + }, + "RelationshipCategoryEnum": { + "type": "string", + "enum": ["friend", "incoming_request", "outgoing_request", "blocked"] + }, + "RemoveUserRelationshipsResponse": { + "type": "object", + "properties": {"removed_count": {"$ref": "#/components/schemas/Int32Type"}}, + "required": ["removed_count"], + "additionalProperties": false + }, + "ListUserRelationshipsResponse": { + "type": "object", + "properties": { + "friends": {"type": "array", "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"}}, + "incoming_requests": { + "type": "array", + "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"} + }, + "outgoing_requests": { + "type": "array", + "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"} + }, + "blocked": {"type": "array", "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"}} + }, + "required": ["friends", "incoming_requests", "outgoing_requests", "blocked"], + "additionalProperties": false + }, + "AdminUserClearFieldsRequest": { + "type": "object", + "properties": { + "fields": { + "maxItems": 10, + "type": "array", + "items": { + "description": "User profile field that can be cleared", + "x-enumNames": ["avatar", "banner", "bio", "pronouns", "global_name"], + "x-enumDescriptions": [ + "User profile avatar image", + "User profile banner image", + "User biography text", + "User pronouns", + "User display name" + ], + "enum": ["avatar", "banner", "bio", "pronouns", "global_name"], + "type": "string" + }, + "description": "List of profile fields to clear" + } + }, + "required": ["fields"] + }, + "AdminUserPremiumFlagsUpdateRequest": { + "type": "object", + "properties": { + "add_flags": { + "default": [], + "description": "Premium flags to add", + "maxItems": 64, + "type": "array", + "items": { + "description": "A single premium flag value to add or remove", + "allOf": [{"$ref": "#/components/schemas/PremiumFlags"}] + } + }, + "remove_flags": { + "default": [], + "description": "Premium flags to remove", + "maxItems": 64, + "type": "array", + "items": { + "description": "A single premium flag value to add or remove", + "allOf": [{"$ref": "#/components/schemas/PremiumFlags"}] + } + } + } + }, + "AdminUserPhoneVerificationRequest": { + "type": "object", + "properties": { + "has_verified_phone": { + "type": "boolean", + "description": "Whether the user should be treated as having completed phone verification" + } + }, + "required": ["has_verified_phone"] + }, + "DeleteAllUserMessagesResponse": { + "type": "object", + "properties": { + "success": {"type": "boolean", "enum": [true]}, + "dry_run": {"type": "boolean"}, + "channel_count": {"$ref": "#/components/schemas/Int32Type"}, + "message_count": {"$ref": "#/components/schemas/Int32Type"}, + "job_id": {"type": "string"} + }, + "required": ["success", "dry_run", "channel_count", "message_count"], + "additionalProperties": false + }, + "AdminUserMessageShredRequest": { + "type": "object", + "properties": { + "entries": { + "minItems": 1, + "maxItems": 1000, + "type": "array", + "items": { + "type": "object", + "properties": { + "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, + "message_id": {"$ref": "#/components/schemas/SnowflakeType"} + }, + "required": ["channel_id", "message_id"] + } + } + }, + "required": ["entries"] + }, + "MessageShredResponse": { + "type": "object", + "properties": { + "success": {"type": "boolean", "enum": [true]}, + "job_id": {"type": "string"}, + "requested": {"type": "integer", "minimum": 0, "maximum": 9007199254740991} + }, + "required": ["success", "job_id"], + "additionalProperties": false + }, + "ListUserGuildsResponse": { + "type": "object", + "properties": {"guilds": {"type": "array", "items": {"$ref": "#/components/schemas/GuildAdminResponse"}}}, + "required": ["guilds"], + "additionalProperties": false + }, + "AdminUserFlagsUpdateRequest": { + "type": "object", + "properties": { + "add_flags": { + "default": [], + "description": "User flags to add", + "maxItems": 64, + "type": "array", + "items": { + "description": "A single user flag value to add or remove", + "allOf": [{"$ref": "#/components/schemas/UserFlags"}] + } + }, + "remove_flags": { + "default": [], + "description": "User flags to remove", + "maxItems": 64, + "type": "array", + "items": { + "description": "A single user flag value to add or remove", + "allOf": [{"$ref": "#/components/schemas/UserFlags"}] + } + } + } + }, + "AdminUserEmailUpdateRequest": { + "type": "object", + "properties": { + "email": { + "description": "New email address for the user", + "allOf": [{"$ref": "#/components/schemas/EmailType"}] + } + }, + "required": ["email"] + }, + "AdminUserDmChannelType": { + "description": "Kind of direct message channel to list", + "x-enumNames": ["DM", "GROUP_DM"], + "x-enumDescriptions": ["One-to-one direct message channels", "Group direct message channels"], + "enum": ["dm", "group_dm"], + "type": "string" + }, + "AdminUserDmChannelListResponse": { + "anyOf": [ + { + "type": "object", + "properties": { + "channels": { + "maxItems": 200, + "type": "array", + "items": { + "type": "object", + "properties": { + "channel_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "channel_type": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, + "channel_nsfw": {"nullable": true, "type": "boolean"}, + "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "recipient_ids": { + "maxItems": 100, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"} + }, + "recipients": { + "maxItems": 100, + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "username": {"type": "string"}, + "discriminator": {"type": "string"}, + "global_name": {"nullable": true, "type": "string"}, + "avatar": {"nullable": true, "type": "string"} + }, + "required": ["id", "username", "discriminator", "global_name", "avatar"], + "additionalProperties": false + } + }, + "last_message_id": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "is_open": {"type": "boolean"}, + "name": {"nullable": true, "type": "string"}, + "icon": {"nullable": true, "type": "string"}, + "owner_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]} + }, + "required": [ + "channel_id", + "channel_type", + "channel_nsfw", + "guild_nsfw_level", + "recipient_ids", + "recipients", + "last_message_id", + "is_open", + "name", + "icon", + "owner_id" + ], + "additionalProperties": false + } + } + }, + "required": ["channels"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "channels": { + "maxItems": 500, + "type": "array", + "items": { + "type": "object", + "properties": { + "channel_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "channel_type": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, + "channel_nsfw": {"nullable": true, "type": "boolean"}, + "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "recipient_ids": { + "maxItems": 100, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"} + }, + "recipients": { + "maxItems": 100, + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "username": {"type": "string"}, + "discriminator": {"type": "string"}, + "global_name": {"nullable": true, "type": "string"}, + "avatar": {"nullable": true, "type": "string"} + }, + "required": ["id", "username", "discriminator", "global_name", "avatar"], + "additionalProperties": false + } + }, + "last_message_id": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "is_open": {"type": "boolean"}, + "name": {"nullable": true, "type": "string"}, + "icon": {"nullable": true, "type": "string"}, + "owner_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]} + }, + "required": [ + "channel_id", + "channel_type", + "channel_nsfw", + "guild_nsfw_level", + "recipient_ids", + "recipients", + "last_message_id", + "is_open", + "name", + "icon", + "owner_id" + ], + "additionalProperties": false + } + } + }, + "required": ["channels"], + "additionalProperties": false + } + ] + }, + "AdminUserDeletionScheduleRequest": { + "type": "object", + "properties": { + "reason_code": { + "description": "Code indicating the reason for deletion", + "allOf": [{"$ref": "#/components/schemas/DeletionReasonCode"}] + }, + "public_reason": {"description": "Public-facing reason for the deletion", "type": "string"}, + "days_until_deletion": { + "default": 60, + "description": "Number of days until the account is deleted", + "type": "integer", + "minimum": 1, + "maximum": 365 + } + }, + "required": ["reason_code"] + }, + "AdminUserDobUpdateRequest": { + "type": "object", + "properties": {"date_of_birth": {"description": "New date of birth in YYYY-MM-DD format", "type": "string"}}, + "required": ["date_of_birth"] + }, + "ListUserChangeLogResponseSchema": { + "type": "object", + "properties": { + "entries": { + "maxItems": 200, + "type": "array", + "items": { + "type": "object", + "properties": { + "event_id": {"type": "string"}, + "field": {"type": "string"}, + "old_value": {"nullable": true, "type": "string"}, + "new_value": {"nullable": true, "type": "string"}, + "reason": {"nullable": true, "type": "string"}, + "actor_user_id": {"nullable": true, "type": "string"}, + "event_at": {"type": "string"} + }, + "required": ["event_id", "field", "old_value", "new_value", "reason", "actor_user_id", "event_at"], + "additionalProperties": false + } + }, + "next_page_token": {"nullable": true, "type": "string"} + }, + "required": ["entries", "next_page_token"], + "additionalProperties": false + }, + "AdminUserBotStatusRequest": { + "type": "object", + "properties": {"bot": {"type": "boolean", "description": "Whether the user should be marked as a bot"}}, + "required": ["bot"] + }, + "AdminUserBanRequest": { + "type": "object", + "properties": { + "duration_hours": { + "type": "integer", + "minimum": 0, + "maximum": 8760, + "description": "Duration of the ban in hours. Use 0 for a permanent ban (until manually unbanned)." + }, + "reason": {"description": "Reason for the temporary ban", "type": "string"} + }, + "required": ["duration_hours"] + }, + "BanUserAvatarRequest": { + "type": "object", + "properties": {"reason": {"type": "string"}, "notes": {"type": "string"}} + }, + "BanUserAvatarResponseSchema": { + "type": "object", + "properties": {"hash_short": {"type": "string", "minLength": 1, "maxLength": 16}}, + "required": ["hash_short"], + "additionalProperties": false + }, + "AdminArchiveCreateRequest": { + "type": "object", + "properties": { + "include_attachments": { + "default": false, + "description": "Whether to include attachment binaries in the archive", + "type": "boolean" + } + } + }, + "AdminArchiveResponseSchema": { + "type": "object", + "properties": { + "archive_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "subject_type": {"allOf": [{"$ref": "#/components/schemas/ArchiveSubjectTypeSchema"}]}, + "subject_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "requested_by": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "requested_at": {"type": "string"}, + "started_at": {"nullable": true, "type": "string"}, + "completed_at": {"nullable": true, "type": "string"}, + "failed_at": {"nullable": true, "type": "string"}, + "file_size": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 64}, + "progress_percent": {"type": "number"}, + "progress_step": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "error_message": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 4000}, + "download_url_expires_at": {"nullable": true, "type": "string"}, + "expires_at": {"nullable": true, "type": "string"} + }, + "required": [ + "archive_id", + "subject_type", + "subject_id", + "requested_by", + "requested_at", + "started_at", + "completed_at", + "failed_at", + "file_size", + "progress_percent", + "progress_step", + "error_message", + "download_url_expires_at", + "expires_at" + ], + "additionalProperties": false + }, + "ListApplicationsResponse": { + "type": "object", + "properties": { + "applications": {"type": "array", "items": {"$ref": "#/components/schemas/ApplicationAdminResponse"}} + }, + "required": ["applications"], + "additionalProperties": false + }, + "AdminUserAclsRequest": { "type": "object", "properties": { "acls": { - "type": "array", - "items": {"type": "string"}, "maxItems": 112, - "description": "Every admin access control permission the admin API recognises" + "type": "array", + "items": {"$ref": "#/components/schemas/AdminAclType"}, + "description": "List of access control permissions to assign" } }, "required": ["acls"] }, - "Error": { + "LookupUserResponse": { + "type": "object", + "properties": {"users": {"type": "array", "items": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}}, + "required": ["users"], + "additionalProperties": false + }, + "AdminUsersMeResponse": { + "type": "object", + "properties": {"user": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}, + "required": ["user"], + "additionalProperties": false + }, + "SnowflakeStringType": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "format": "snowflake"}, + "SearchUsersResponse": { "type": "object", "properties": { - "code": {"$ref": "#/components/schemas/APIErrorCode"}, - "message": {"type": "string", "description": "Human-readable error message"}, - "errors": { + "users": {"type": "array", "items": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}, + "total": {"type": "number"} + }, + "required": ["users", "total"], + "additionalProperties": false + }, + "HeapSnapshotResponse": {"type": "string", "format": "binary", "description": "V8 heap snapshot file"}, + "SendSystemDmRequest": { + "type": "object", + "properties": { + "content": { + "type": "string", + "minLength": 1, + "maxLength": 4000, + "description": "Message content to send to each recipient" + }, + "user_ids": { + "minItems": 1, + "maxItems": 10000, "type": "array", - "description": "Field-specific validation errors", - "items": {"$ref": "#/components/schemas/ValidationErrorItem"} + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "Recipient user IDs. Each receives the same content as a system DM." } }, - "required": ["code", "message"] + "required": ["content", "user_ids"] }, - "APIErrorCode": { - "type": "string", - "enum": [ - "ACCESS_DENIED", - "BAD_GATEWAY", - "BAD_REQUEST", - "BLUESKY_OAUTH_AUTHORIZATION_FAILED", - "BLUESKY_OAUTH_CALLBACK_FAILED", - "BLUESKY_OAUTH_NOT_ENABLED", - "BLUESKY_OAUTH_STATE_INVALID", - "ACCOUNT_SUSPENDED_PERMANENTLY", - "ACCOUNT_SUSPENDED_TEMPORARILY", - "ACCOUNT_SUSPICIOUS_ACTIVITY", - "ACCOUNT_TOO_NEW_FOR_GUILD", - "ACLS_MUST_BE_NON_EMPTY", - "ADMIN_API_KEY_NOT_FOUND", - "APPLICATION_NOT_OWNED", - "ALREADY_FRIENDS", - "BOTS_CANNOT_CREATE_GUILDS", - "BOTS_CANNOT_SEND_FRIEND_REQUESTS", - "BOT_ALREADY_IN_GUILD", - "BOT_IS_PRIVATE", - "BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED", - "BOT_USER_AUTH_SESSION_CREATION_DENIED", - "BOT_USER_GENERATION_FAILED", - "BOT_USER_NOT_FOUND", - "CALL_ALREADY_EXISTS", - "CANNOT_EDIT_OTHER_USER_MESSAGE", - "CANNOT_EXECUTE_ON_DM", - "CANNOT_BLOCK_SYSTEM_USER", - "CANNOT_MODIFY_SYSTEM_WEBHOOK", - "CANNOT_REDEEM_PLUTONIUM_WITH_VISIONARY", - "CANNOT_REPORT_GUILD", - "CANNOT_REPORT_OWN_GUILD", - "CANNOT_REPORT_OWN_MESSAGE", - "CANNOT_REPORT_YOURSELF", - "CANNOT_SEND_EMPTY_MESSAGE", - "CANNOT_SEND_FRIEND_REQUEST_TO_BLOCKED_USER", - "CANNOT_SEND_FRIEND_REQUEST_TO_SELF", - "CANNOT_SEND_MESSAGES_IN_NON_TEXT_CHANNEL", - "CANNOT_SEND_MESSAGES_TO_USER", - "CANNOT_TRANSFER_OWNERSHIP_TO_BOT", - "CANNOT_SHRINK_RESERVED_SLOTS", - "CAPTCHA_REQUIRED", - "COMMUNICATION_DISABLED", - "CONNECTION_ALREADY_EXISTS", - "CONNECTION_INITIATION_TOKEN_INVALID", - "CONNECTION_INVALID_TYPE", - "CONNECTION_LIMIT_REACHED", - "CONNECTION_NOT_FOUND", - "CONNECTION_VERIFICATION_FAILED", - "CONFLICT", - "CONTENT_BLOCKED", - "DELETION_FAILED", - "DISCOVERY_ALREADY_APPLIED", - "DISCOVERY_APPLICATION_ALREADY_REVIEWED", - "DISCOVERY_APPLICATION_NOT_FOUND", - "DISCOVERY_DISABLED", - "DISCOVERY_INSUFFICIENT_MEMBERS", - "DISCOVERY_NOT_DISCOVERABLE", - "DISCRIMINATOR_REQUIRED", - "EMAIL_SERVICE_NOT_TESTABLE", - "EMAIL_VERIFICATION_REQUIRED", - "DIRECT_MESSAGE_EMAIL_VERIFICATION_REQUIRED", - "FRIEND_REQUEST_EMAIL_VERIFICATION_REQUIRED", - "GUILD_CREATION_EMAIL_VERIFICATION_REQUIRED", - "GUILD_EMAIL_VERIFICATION_REQUIRED", - "MFA_EMAIL_VERIFICATION_REQUIRED", - "PROFILE_EMAIL_VERIFICATION_REQUIRED", - "PURCHASE_EMAIL_VERIFICATION_REQUIRED", - "REACTION_EMAIL_VERIFICATION_REQUIRED", - "REPORT_EMAIL_VERIFICATION_REQUIRED", - "REGISTRATION_CLOSED", - "REGISTRATION_PENDING_APPROVAL", - "REGISTRATION_REJECTED", - "REGISTRATION_URL_INVALID", - "EXPLICIT_CONTENT_CANNOT_BE_SENT", - "FEATURE_NOT_AVAILABLE_SELF_HOSTED", - "FEATURE_TEMPORARILY_DISABLED", - "FILE_SIZE_TOO_LARGE", - "FORBIDDEN", - "FRIEND_REQUEST_BLOCKED", - "GATEWAY_TIMEOUT", - "GENERAL_ERROR", - "GONE", - "GIFT_CODE_ALREADY_REDEEMED", - "GUILD_PHONE_VERIFICATION_REQUIRED", - "GUILD_TEMPLATE_INVALID", - "GUILD_VERIFICATION_REQUIRED", - "HANDOFF_CODE_EXPIRED", - "HARVEST_EXPIRED", - "HARVEST_FAILED", - "HARVEST_NOT_READY", - "INTERNAL_SERVER_ERROR", - "INVALID_ACLS_FORMAT", - "INVALID_API_ORIGIN", - "INVALID_AUTH_TOKEN", - "INVALID_BOT_FLAG", - "INVALID_CAPTCHA", - "INVALID_CHANNEL_TYPE_FOR_CALL", - "INVALID_CHANNEL_TYPE", - "INVALID_DSA_REPORT_TARGET", - "INVALID_DSA_TICKET", - "INVALID_DSA_VERIFICATION_CODE", - "INVALID_FLAGS_FORMAT", - "INVALID_FORM_BODY", - "INVALID_HANDOFF_CODE", - "INVALID_PERMISSIONS_INTEGER", - "INVALID_PERMISSIONS_NEGATIVE", - "INVALID_PHONE_NUMBER", - "INVALID_PHONE_VERIFICATION_CODE", - "INVALID_REQUEST", - "INVALID_STREAM_KEY_FORMAT", - "INVALID_STREAM_THUMBNAIL_PAYLOAD", - "INVALID_SUSPICIOUS_FLAGS_FORMAT", - "INVALID_SYSTEM_FLAG", - "INVALID_TIMESTAMP", - "INVALID_TOKEN", - "INVALID_WEBAUTHN_AUTHENTICATION_COUNTER", - "INVALID_WEBAUTHN_CREDENTIAL_COUNTER", - "INVALID_WEBAUTHN_CREDENTIAL", - "INVALID_WEBAUTHN_PUBLIC_KEY_FORMAT", - "INVITES_DISABLED", - "IP_AUTHORIZATION_REQUIRED", - "IP_AUTHORIZATION_RESEND_COOLDOWN", - "IP_AUTHORIZATION_RESEND_LIMIT_EXCEEDED", - "GLOBAL_IP_BANNED", - "GLOBAL_IP_TEMPORARILY_BANNED", - "IP_BAN_DECLINED", - "MAX_APPLICATIONS", - "MAX_BOOKMARKS", - "MAX_CATEGORY_CHANNELS", - "MAX_EMOJIS", - "MAX_FAVORITE_MEMES", - "MAX_FRIENDS", - "MAX_GROUP_DM_RECIPIENTS", - "MAX_GROUP_DMS", - "GROUP_DM_RECIPIENTS_NOT_ADDABLE", - "MAX_GUILD_CHANNELS", - "MAX_GUILD_MEMBERS", - "MAX_GUILD_ROLES", - "MAX_GUILDS", - "MAX_INVITES", - "MAX_REACTIONS", - "MAX_STICKERS", - "MAX_WEBHOOKS_PER_CHANNEL", - "MAX_WEBHOOKS_PER_GUILD", - "NCMEC_ALREADY_SUBMITTED", - "NCMEC_SUBMISSION_FAILED", - "MEDIA_METADATA_ERROR", - "METHOD_NOT_ALLOWED", - "MISSING_ACCESS", - "MISSING_ACL", - "MISSING_AUTHORIZATION", - "MISSING_OAUTH_SCOPE", - "MISSING_PERMISSIONS", - "NO_ACTIVE_CALL", - "NO_ACTIVE_SUBSCRIPTION", - "NOT_FOUND", - "NOT_IMPLEMENTED", - "NO_PASSKEYS_REGISTERED", - "NO_PENDING_DELETION", - "NO_USERS_WITH_FLUXERTAG_EXIST", - "NOT_A_BOT_APPLICATION", - "NOT_FRIENDS_WITH_USER", - "NSFW_CONTENT_AGE_RESTRICTED", - "PASSKEY_AUTHENTICATION_FAILED", - "PHONE_ADD_NOT_ELIGIBLE", - "PHONE_ALREADY_USED", - "PHONE_COUNTRY_NOT_SUPPORTED", - "PHONE_GATE_ESCAPE_UNAVAILABLE", - "PHONE_INBOUND_VERIFICATION_REQUIRED", - "PHONE_LOOKUP_UNAVAILABLE", - "PHONE_NUMBER_NOT_IN_SERVICE", - "PHONE_NUMBER_NOT_MOBILE", - "PHONE_RATE_LIMIT_EXCEEDED", - "PHONE_VERIFICATION_NEEDS_REVIEW", - "PHONE_VERIFICATION_REQUIRED", - "PREMIUM_PURCHASE_BLOCKED", - "PREVIEW_MUST_BE_JPEG", - "PROCESSING_FAILED", - "RATE_LIMITED", - "REPORT_ALREADY_RESOLVED", - "REPORT_BANNED", - "RESPONSE_VALIDATION_ERROR", - "RESOURCE_LOCKED", - "SERVICE_UNAVAILABLE", - "SESSION_TOKEN_MISMATCH", - "SINGLE_COMMUNITY_CANNOT_CREATE_GUILDS", - "SINGLE_COMMUNITY_CANNOT_DELETE", - "SINGLE_COMMUNITY_CANNOT_LEAVE", - "INSTANCE_POLICY_TRANSITION_NOT_ALLOWED", - "SLOWMODE_RATE_LIMITED", - "SMS_VERIFICATION_UNAVAILABLE", - "SSO_REQUIRED", - "STREAM_KEY_CHANNEL_MISMATCH", - "STREAM_KEY_SCOPE_MISMATCH", - "STRIPE_ERROR", - "STRIPE_GIFT_REDEMPTION_IN_PROGRESS", - "STRIPE_INVALID_PRODUCT", - "STRIPE_INVALID_PRODUCT_CONFIGURATION", - "STRIPE_NO_ACTIVE_SUBSCRIPTION", - "STRIPE_NO_PURCHASE_HISTORY", - "STRIPE_REFUND_OUTSIDE_WINDOW", - "STRIPE_REFUND_COOLDOWN_ACTIVE", - "STRIPE_NO_SUBSCRIPTION", - "STRIPE_PAYMENT_NOT_AVAILABLE", - "STRIPE_SUBSCRIPTION_ALREADY_CANCELING", - "STRIPE_SUBSCRIPTION_NOT_CANCELING", - "STRIPE_WEBHOOK_NOT_AVAILABLE", - "STRIPE_WEBHOOK_SIGNATURE_INVALID", - "STRIPE_WEBHOOK_SIGNATURE_MISSING", - "DIRECT_MESSAGES_DISABLED", - "DONATION_AMOUNT_INVALID", - "DONATION_MAGIC_LINK_EXPIRED", - "DONATION_MAGIC_LINK_INVALID", - "DONATION_MAGIC_LINK_USED", - "SUDO_MODE_REQUIRED", - "TAG_ALREADY_TAKEN", - "TEMPORARY_INVITE_REQUIRES_PRESENCE", - "TEST_HARNESS_DISABLED", - "TEST_HARNESS_FORBIDDEN", - "TWO_FA_NOT_ENABLED", - "TWO_FACTOR_REQUIRED", - "UNAUTHORIZED", - "UNCLAIMED_ACCOUNT_CANNOT_ACCEPT_FRIEND_REQUESTS", - "UNCLAIMED_ACCOUNT_CANNOT_ADD_REACTIONS", - "UNCLAIMED_ACCOUNT_CANNOT_CREATE_APPLICATIONS", - "UNCLAIMED_ACCOUNT_CANNOT_CREATE_GUILDS", - "UNCLAIMED_ACCOUNT_CANNOT_JOIN_GROUP_DMS", - "UNCLAIMED_ACCOUNT_CANNOT_JOIN_ONE_ON_ONE_VOICE_CALLS", - "UNCLAIMED_ACCOUNT_CANNOT_JOIN_VOICE_CHANNELS", - "UNCLAIMED_ACCOUNT_CANNOT_MAKE_PURCHASES", - "UNCLAIMED_ACCOUNT_CANNOT_SEND_DIRECT_MESSAGES", - "UNCLAIMED_ACCOUNT_CANNOT_SEND_FRIEND_REQUESTS", - "UNCLAIMED_ACCOUNT_CANNOT_SEND_MESSAGES", - "UNCLAIMED_ACCOUNT_CANNOT_SUBMIT_REPORTS", - "UNKNOWN_CHANNEL", - "UNKNOWN_EMOJI", - "UNKNOWN_FAVORITE_MEME", - "UNKNOWN_GIFT_CODE", - "UNKNOWN_GUILD", - "UNKNOWN_HARVEST", - "UNKNOWN_INVITE", - "UNKNOWN_MEMBER", - "UNKNOWN_MESSAGE", - "UNKNOWN_REPORT", - "UNKNOWN_ROLE", - "UNKNOWN_STICKER", - "UNKNOWN_SUSPICIOUS_FLAG", - "UNKNOWN_USER_FLAG", - "UNKNOWN_USER", - "UNKNOWN_VOICE_REGION", - "UNKNOWN_VOICE_SERVER", - "UNKNOWN_WEBAUTHN_CREDENTIAL", - "UNKNOWN_APPLICATION", - "UNKNOWN_WEBHOOK", - "USERNAME_NOT_AVAILABLE", - "UPDATE_FAILED", - "USER_BANNED_FROM_GUILD", - "USER_IP_BANNED_FROM_GUILD", - "USER_NOT_IN_VOICE", - "USER_OWNS_GUILDS", - "VALIDATION_ERROR", - "VOICE_CHANNEL_FULL", - "WEBAUTHN_CREDENTIAL_LIMIT_REACHED", - "AGE_VERIFICATION_ALREADY_VERIFIED" - ], - "description": "Error codes returned by API operations" - }, - "ValidationErrorItem": { + "SendSystemDmResponse": { "type": "object", "properties": { - "path": {"type": "string", "description": "Field path that failed validation"}, - "code": {"type": "string", "description": "Machine-readable validation error code"}, - "message": {"type": "string", "description": "Human-readable validation error message"} + "recipient_count": { + "description": "Number of recipients the worker job was queued to deliver to", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + } }, - "required": ["path", "message"] + "required": ["recipient_count"], + "additionalProperties": false + }, + "RefreshSearchIndexRequest": { + "type": "object", + "properties": { + "guild_id": { + "description": "Specific guild ID to reindex", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "user_id": { + "description": "Specific user ID to reindex", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + } + } + }, + "RefreshSearchIndexResponse": { + "type": "object", + "properties": {"success": {"type": "boolean", "enum": [true]}, "job_id": {"type": "string"}}, + "required": ["success", "job_id"], + "additionalProperties": false + }, + "IndexRefreshStatusResponse": { + "anyOf": [ + { + "type": "object", + "properties": {"status": {"type": "string", "enum": ["not_found"], "description": "Job was not found"}}, + "required": ["status"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "status": { + "description": "Current status of the index refresh job", + "x-enumNames": ["in_progress", "completed", "failed"], + "x-enumDescriptions": [ + "Index refresh is currently in progress", + "Index refresh completed successfully", + "Index refresh failed" + ], + "enum": ["in_progress", "completed", "failed"], + "type": "string" + }, + "index_type": {"type": "string", "description": "Type of index being refreshed"}, + "total": {"description": "Total number of items to index", "type": "number"}, + "indexed": {"description": "Number of items indexed so far", "type": "number"}, + "started_at": {"description": "ISO 8601 timestamp when the job started", "type": "string"}, + "completed_at": {"description": "ISO 8601 timestamp when the job completed", "type": "string"}, + "failed_at": {"description": "ISO 8601 timestamp when the job failed", "type": "string"}, + "error": {"description": "Error message if the job failed", "type": "string"} + }, + "required": ["status", "index_type"], + "additionalProperties": false + } + ] + }, + "UpdateReportRequest": { + "type": "object", + "properties": { + "status": {"type": "string", "enum": ["resolved"], "description": "The status to move the report to"}, + "public_comment": {"description": "Public comment to include with the resolution", "type": "string"} + }, + "required": ["status"] + }, + "ResolveReportResponse": { + "type": "object", + "properties": { + "report_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "status": {"allOf": [{"$ref": "#/components/schemas/ReportStatus"}]}, + "resolved_at": {"nullable": true, "type": "string"}, + "public_comment": {"nullable": true, "type": "string"} + }, + "required": ["report_id", "status", "resolved_at", "public_comment"], + "additionalProperties": false + }, + "ReportAdminResponseSchema": { + "type": "object", + "properties": { + "report_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "reporter_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "reporter_tag": {"nullable": true, "type": "string"}, + "reporter_username": {"nullable": true, "type": "string"}, + "reporter_global_name": {"nullable": true, "type": "string"}, + "reporter_discriminator": {"nullable": true, "type": "string"}, + "reporter_email": {"nullable": true, "type": "string"}, + "reporter_full_legal_name": {"nullable": true, "type": "string"}, + "reporter_country_of_residence": {"nullable": true, "type": "string"}, + "reported_at": {"type": "string"}, + "status": {"allOf": [{"$ref": "#/components/schemas/ReportStatus"}]}, + "report_type": {"allOf": [{"$ref": "#/components/schemas/ReportType"}]}, + "category": {"nullable": true, "type": "string"}, + "additional_info": {"nullable": true, "type": "string"}, + "reported_user_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "reported_user_tag": {"nullable": true, "type": "string"}, + "reported_user_username": {"nullable": true, "type": "string"}, + "reported_user_global_name": {"nullable": true, "type": "string"}, + "reported_user_discriminator": {"nullable": true, "type": "string"}, + "reported_user_avatar_hash": {"nullable": true, "type": "string"}, + "reported_guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "reported_guild_name": {"nullable": true, "type": "string"}, + "reported_guild_icon_hash": {"nullable": true, "type": "string"}, + "reported_message_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "reported_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "reported_channel_name": {"nullable": true, "type": "string"}, + "reported_channel_nsfw": {"nullable": true, "type": "boolean"}, + "reported_guild_invite_code": {"nullable": true, "type": "string"}, + "reported_guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "reported_guild_nsfw": {"nullable": true, "type": "boolean"}, + "reported_guild_content_warning_level": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] + }, + "reported_guild_content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "reported_channel_nsfw_override": {"nullable": true, "type": "boolean"}, + "reported_channel_content_warning_level": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] + }, + "reported_channel_content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "reported_channel_effective_nsfw": {"nullable": true, "type": "boolean"}, + "reported_channel_effective_content_warning_level": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] + }, + "reported_channel_effective_content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "resolved_at": {"nullable": true, "type": "string"}, + "resolved_by_admin_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "public_comment": {"nullable": true, "type": "string"}, + "mutual_dm_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "message_context": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "channel_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "channel_nsfw": {"nullable": true, "type": "boolean"}, + "channel_content_warning_level": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] + }, + "channel_content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "guild_nsfw": {"nullable": true, "type": "boolean"}, + "guild_content_warning_level": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] + }, + "guild_content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "content": {"type": "string"}, + "timestamp": {"type": "string"}, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "filename": {"type": "string", "minLength": 1, "maxLength": 256}, + "url": {"type": "string", "minLength": 1, "maxLength": 2048}, + "nsfw": {"nullable": true, "type": "boolean"}, + "content_type": {"nullable": true, "type": "string"}, + "width": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, + "height": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, + "size": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}] + }, + "ncmec_status": { + "description": "NCMEC submission status", + "x-enumNames": ["not_submitted", "submitting", "submitted", "failed"], + "x-enumDescriptions": [ + "Report has not been submitted to NCMEC", + "Report submission to NCMEC is in progress", + "Report has been submitted to NCMEC", + "Report submission to NCMEC failed" + ], + "enum": ["not_submitted", "submitting", "submitted", "failed"], + "type": "string" + }, + "ncmec_report_id": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "ncmec_failure_reason": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 4000} + }, + "required": [ + "id", + "filename", + "url", + "nsfw", + "content_type", + "width", + "height", + "ncmec_status", + "ncmec_report_id", + "ncmec_failure_reason" + ], + "additionalProperties": false + } + }, + "author_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "author_username": {"type": "string"}, + "author_global_name": {"nullable": true, "type": "string"}, + "author_discriminator": {"type": "string"}, + "author_avatar": {"nullable": true, "type": "string"}, + "user_prior_ncmec_report_ids": { + "maxItems": 100, + "type": "array", + "items": {"type": "string", "minLength": 1, "maxLength": 256} + } + }, + "required": [ + "id", + "channel_id", + "channel_nsfw", + "guild_id", + "guild_nsfw_level", + "content", + "timestamp", + "attachments", + "author_id", + "author_username", + "author_global_name", + "author_discriminator", + "author_avatar" + ], + "additionalProperties": false + } + }, + "message_responses": {"type": "array", "items": {"$ref": "#/components/schemas/MessageResponseSchema"}} + }, + "required": [ + "report_id", + "reporter_id", + "reporter_tag", + "reporter_username", + "reporter_global_name", + "reporter_discriminator", + "reporter_email", + "reporter_full_legal_name", + "reporter_country_of_residence", + "reported_at", + "status", + "report_type", + "category", + "additional_info", + "reported_user_id", + "reported_user_tag", + "reported_user_username", + "reported_user_global_name", + "reported_user_discriminator", + "reported_user_avatar_hash", + "reported_guild_id", + "reported_guild_name", + "reported_guild_icon_hash", + "reported_message_id", + "reported_channel_id", + "reported_channel_name", + "reported_channel_nsfw", + "reported_guild_invite_code", + "reported_guild_nsfw_level", + "resolved_at", + "resolved_by_admin_id", + "public_comment" + ], + "additionalProperties": false + }, + "AdminReportListResponse": { + "type": "object", + "properties": { + "reports": {"type": "array", "items": {"$ref": "#/components/schemas/ReportAdminResponseSchema"}}, + "total": {"type": "number"}, + "offset": {"type": "number"}, + "limit": {"type": "number"} + }, + "required": ["reports", "total", "offset", "limit"], + "additionalProperties": false + }, + "MessageShredStatusResponse": { + "anyOf": [ + { + "type": "object", + "properties": {"status": {"type": "string", "enum": ["not_found"]}}, + "required": ["status"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "status": { + "description": "Current message shred job status", + "x-enumNames": ["in_progress", "completed", "failed"], + "x-enumDescriptions": [ + "Shredding is currently running", + "Shredding completed successfully", + "Shredding failed" + ], + "enum": ["in_progress", "completed", "failed"], + "type": "string" + }, + "requested": {"$ref": "#/components/schemas/Int32Type"}, + "total": {"$ref": "#/components/schemas/Int32Type"}, + "processed": {"$ref": "#/components/schemas/Int32Type"}, + "skipped": {"$ref": "#/components/schemas/Int32Type"}, + "started_at": {"type": "string"}, + "completed_at": {"type": "string"}, + "failed_at": {"type": "string"}, + "error": {"type": "string", "minLength": 1, "maxLength": 4000} + }, + "required": ["status", "requested", "total", "processed", "skipped"], + "additionalProperties": false + } + ] + }, + "ReportAttachmentToNcmecRequest": { + "type": "object", + "properties": { + "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, + "message_id": {"$ref": "#/components/schemas/SnowflakeType"}, + "attachment_id": {"$ref": "#/components/schemas/SnowflakeType"}, + "filename": {"type": "string", "minLength": 1, "maxLength": 255}, + "source_report_id": {"allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, + "reporter_full_name": {"type": "string", "minLength": 1, "maxLength": 200}, + "confirmed_viewed": {"type": "boolean", "enum": [true]} + }, + "required": ["channel_id", "message_id", "attachment_id", "filename", "reporter_full_name", "confirmed_viewed"] + }, + "NcmecAttachmentSubmitResultResponse": { + "type": "object", + "properties": { + "success": {"type": "boolean", "enum": [true]}, + "ncmec_report_id": {"type": "string", "minLength": 1, "maxLength": 256}, + "audit_log_reason": {"type": "string", "minLength": 1, "maxLength": 4000} + }, + "required": ["success", "ncmec_report_id", "audit_log_reason"], + "additionalProperties": false + }, + "AdminMessageSearchResponse": { + "anyOf": [ + { + "type": "object", + "properties": { + "messages": { + "maxItems": 100, + "type": "array", + "items": {"$ref": "#/components/schemas/AdminMessageSchema"} + }, + "message_responses": { + "maxItems": 100, + "type": "array", + "items": {"$ref": "#/components/schemas/MessageResponseSchema"} + }, + "total": {"type": "integer", "minimum": 0, "maximum": 9007199254740991} + }, + "required": ["messages", "total"], + "additionalProperties": false + }, + {"$ref": "#/components/schemas/LookupMessageResponse"} + ] + }, + "LimitConfigUpdateRequest": { + "type": "object", + "properties": { + "limit_config": { + "type": "object", + "properties": { + "traitDefinitions": { + "description": "Trait definitions used by rules", + "type": "array", + "items": {"type": "string"} + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"type": "string", "minLength": 1, "description": "Unique rule identifier"}, + "filters": { + "description": "Optional filters that scope the rule", + "type": "object", + "properties": { + "traits": { + "description": "Trait filters that must match for the rule to apply", + "type": "array", + "items": {"type": "string"} + }, + "guildFeatures": { + "description": "Guild feature flags required for the rule to apply", + "type": "array", + "items": {"type": "string"} + } + } + }, + "limits": { + "type": "object", + "additionalProperties": {"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}, + "description": "Per-limit key values" + } + }, + "required": ["id", "limits"] + }, + "description": "Limit rules" + } + }, + "required": ["rules"], + "description": "New limit configuration snapshot" + } + }, + "required": ["limit_config"] + }, + "LimitConfigGetResponse": { + "type": "object", + "properties": { + "limit_config": { + "type": "object", + "properties": { + "traitDefinitions": {"type": "array", "items": {"type": "string"}}, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"type": "string", "minLength": 1, "description": "Unique rule identifier"}, + "filters": { + "description": "Optional filters that scope the rule", + "type": "object", + "properties": { + "traits": { + "description": "Trait filters that must match for the rule to apply", + "type": "array", + "items": {"type": "string"} + }, + "guildFeatures": { + "description": "Guild feature flags required for the rule to apply", + "type": "array", + "items": {"type": "string"} + } + }, + "additionalProperties": false + }, + "limits": { + "type": "object", + "additionalProperties": {"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}, + "description": "Per-limit key values" + }, + "modifiedFields": {"type": "array", "items": {"type": "string"}} + }, + "required": ["id", "limits"], + "additionalProperties": false + } + } + }, + "required": ["traitDefinitions", "rules"], + "additionalProperties": false + }, + "limit_config_json": {"type": "string"}, + "self_hosted": {"type": "boolean"}, + "defaults": { + "type": "object", + "additionalProperties": {"type": "object", "additionalProperties": {"type": "number"}} + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "key": {"type": "string"}, + "label": {"type": "string"}, + "description": {"type": "string"}, + "category": {"type": "string"}, + "scope": {"type": "string"}, + "isToggle": {"type": "boolean"}, + "unit": {"type": "string", "enum": ["bytes", "count"]}, + "min": {"type": "number"}, + "max": {"type": "number"} + }, + "required": ["key", "label", "description", "category", "scope", "isToggle"], + "additionalProperties": false + }, + "required": [ + "avatar_max_size", + "emoji_max_size", + "feature_animated_avatar", + "feature_animated_banner", + "feature_custom_discriminator", + "feature_custom_notification_sounds", + "feature_early_access", + "feature_global_expressions", + "feature_higher_video_quality", + "feature_per_guild_profiles", + "feature_voice_entrance_sounds", + "max_attachments_per_message", + "max_bio_length", + "max_bookmarks", + "max_channels_per_category", + "max_custom_backgrounds", + "max_embeds_per_message", + "max_favorite_meme_tags", + "max_favorite_memes", + "max_group_dm_recipients", + "max_group_dms_per_user", + "max_guild_channels", + "max_guild_emojis", + "max_guild_emojis_animated_more", + "max_guild_emojis_animated", + "max_guild_emojis_static_more", + "max_guild_emojis_static", + "max_guild_invites", + "max_guild_members", + "max_guild_roles", + "max_guild_stickers_more", + "max_guild_stickers", + "max_guilds", + "max_attachment_file_size", + "max_message_length", + "max_private_channels_per_user", + "max_reactions_per_message", + "max_relationships", + "max_users_per_message_reaction", + "max_voice_message_duration", + "max_webhooks_per_channel", + "max_webhooks_per_guild", + "sticker_max_size" + ] + }, + "categories": {"type": "object", "additionalProperties": {"type": "string"}}, + "limit_keys": {"type": "array", "items": {"type": "string"}}, + "bounds": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {"min": {"type": "number"}, "max": {"type": "number"}}, + "required": ["min", "max"], + "additionalProperties": false + } + } + }, + "required": [ + "limit_config", + "limit_config_json", + "self_hosted", + "defaults", + "metadata", + "categories", + "limit_keys" + ], + "additionalProperties": false + }, + "CancelJobResponseSchema": { + "type": "object", + "properties": { + "cancelled": { + "type": "boolean", + "description": "True if a cancel request was recorded; false if the job was already terminal." + } + }, + "required": ["cancelled"], + "additionalProperties": false + }, + "GetJobResponseSchema": { + "type": "object", + "properties": {"job": {"$ref": "#/components/schemas/JobLedgerEntrySchema"}}, + "required": ["job"], + "additionalProperties": false + }, + "ActiveJobsResponseSchema": { + "type": "object", + "properties": {"jobs": {"type": "array", "items": {"$ref": "#/components/schemas/JobLedgerEntrySchema"}}}, + "required": ["jobs"], + "additionalProperties": false + }, + "ListJobsResponseSchema": { + "type": "object", + "properties": { + "jobs": {"type": "array", "items": {"$ref": "#/components/schemas/JobLedgerEntrySchema"}}, + "next_cursor": { + "nullable": true, + "type": "object", + "properties": { + "bucket_day": {"type": "string"}, + "created_at": {"type": "string"}, + "job_id": {"$ref": "#/components/schemas/SnowflakeStringType"} + }, + "required": ["bucket_day", "created_at", "job_id"], + "additionalProperties": false + } + }, + "required": ["jobs", "next_cursor"], + "additionalProperties": false + }, + "InstanceConfigResponse": { + "type": "object", + "properties": { + "sso": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "enforced": {"type": "boolean"}, + "display_name": {"nullable": true, "type": "string"}, + "issuer": {"nullable": true, "type": "string"}, + "authorization_url": {"nullable": true, "type": "string"}, + "token_url": {"nullable": true, "type": "string"}, + "userinfo_url": {"nullable": true, "type": "string"}, + "jwks_url": {"nullable": true, "type": "string"}, + "client_id": {"nullable": true, "type": "string"}, + "client_secret_set": {"type": "boolean"}, + "scope": {"nullable": true, "type": "string"}, + "allowed_domains": {"maxItems": 100, "type": "array", "items": {"type": "string"}}, + "auto_provision": {"type": "boolean"}, + "redirect_uri": {"nullable": true, "type": "string"} + }, + "required": [ + "enabled", + "enforced", + "display_name", + "issuer", + "authorization_url", + "token_url", + "userinfo_url", + "jwks_url", + "client_id", + "client_secret_set", + "scope", + "allowed_domains", + "auto_provision", + "redirect_uri" + ], + "additionalProperties": false + }, + "gateway_rollout": {"$ref": "#/components/schemas/GatewayRolloutConfigResponse"}, + "voice_noise_suppression": {"$ref": "#/components/schemas/VoiceNoiseSuppressionConfigResponse"}, + "experiment_delivery": {"$ref": "#/components/schemas/ExperimentDeliveryConfigResponse"}, + "registration": { + "type": "object", + "properties": { + "mode": {"allOf": [{"$ref": "#/components/schemas/InstanceRegistrationModeSchema"}]}, + "admin_registration_urls_enabled": {"type": "boolean"}, + "urls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"type": "string", "minLength": 1, "maxLength": 128}, + "label": {"nullable": true, "type": "string"}, + "created_by_user_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "created_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "expires_at": { + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "max_uses": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 9007199254740991}, + "use_count": {"type": "integer", "minimum": 0, "maximum": 9007199254740991}, + "revoked_at": { + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "approval_required": {"type": "boolean"}, + "last_used_at": { + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "last_used_by_user_id": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + } + }, + "required": [ + "id", + "label", + "created_by_user_id", + "created_at", + "expires_at", + "max_uses", + "use_count", + "revoked_at", + "approval_required", + "last_used_at", + "last_used_by_user_id" + ], + "additionalProperties": false + } + }, + "pending_registrations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "username": {"type": "string"}, + "discriminator": {"type": "integer", "minimum": 0, "maximum": 9999}, + "global_name": {"nullable": true, "type": "string"}, + "email": {"nullable": true, "type": "string"}, + "requested_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "registration_url_id": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 128}, + "client_ip": {"nullable": true, "type": "string"} + }, + "required": [ + "user_id", + "username", + "discriminator", + "global_name", + "email", + "requested_at", + "registration_url_id", + "client_ip" + ], + "additionalProperties": false + } + } + }, + "required": ["mode", "admin_registration_urls_enabled", "urls", "pending_registrations"], + "additionalProperties": false + }, + "self_hosted": {"type": "boolean"}, + "app_public": { + "type": "object", + "properties": { + "branding": { + "type": "object", + "properties": { + "product_name": {"type": "string"}, + "icon_url": {"nullable": true, "type": "string"}, + "symbol_url": {"nullable": true, "type": "string"}, + "logo_url": {"nullable": true, "type": "string"}, + "wordmark_url": {"nullable": true, "type": "string"}, + "favicon_url": {"nullable": true, "type": "string"}, + "theme_color": {"nullable": true, "type": "string"} + }, + "required": [ + "product_name", + "icon_url", + "symbol_url", + "logo_url", + "wordmark_url", + "favicon_url", + "theme_color" + ], + "additionalProperties": false + }, + "setup": { + "type": "object", + "properties": {"configured": {"type": "boolean"}}, + "required": ["configured"], + "additionalProperties": false + }, + "legal": { + "type": "object", + "properties": { + "terms_url": {"nullable": true, "type": "string"}, + "privacy_url": {"nullable": true, "type": "string"} + }, + "required": ["terms_url", "privacy_url"], + "additionalProperties": false + }, + "registration": { + "type": "object", + "properties": {"collect_date_of_birth": {"type": "boolean"}}, + "required": ["collect_date_of_birth"], + "additionalProperties": false + } + }, + "required": ["branding", "setup", "legal", "registration"], + "additionalProperties": false + }, + "policy": { + "type": "object", + "properties": { + "single_community_enabled": {"type": "boolean"}, + "single_community_guild_id": {"nullable": true, "type": "string"}, + "direct_messages_disabled": {"type": "boolean"}, + "direct_messages_locked": {"type": "boolean"}, + "premium_mode": {"type": "string", "enum": ["mirror", "everyone"]}, + "services": { + "type": "object", + "properties": { + "gif_enabled": {"nullable": true, "type": "boolean"}, + "youtube_enabled": {"nullable": true, "type": "boolean"}, + "bluesky_enabled": {"nullable": true, "type": "boolean"} + }, + "required": ["gif_enabled", "youtube_enabled", "bluesky_enabled"], + "additionalProperties": false + }, + "services_resolved": { + "type": "object", + "properties": { + "gif_enabled": {"type": "boolean"}, + "youtube_enabled": {"type": "boolean"}, + "bluesky_enabled": {"type": "boolean"} + }, + "required": ["gif_enabled", "youtube_enabled", "bluesky_enabled"], + "additionalProperties": false + }, + "services_available": { + "type": "object", + "properties": { + "gif": {"type": "boolean"}, + "youtube": {"type": "boolean"}, + "bluesky": {"type": "boolean"} + }, + "required": ["gif", "youtube", "bluesky"], + "additionalProperties": false + }, + "deferred_phone_gate": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "window_hours": {"type": "number"}, + "member_threshold": {"type": "number"} + }, + "required": ["enabled", "window_hours", "member_threshold"], + "additionalProperties": false + } + }, + "required": [ + "single_community_enabled", + "single_community_guild_id", + "direct_messages_disabled", + "direct_messages_locked", + "premium_mode", + "services", + "services_resolved", + "services_available", + "deferred_phone_gate" + ], + "additionalProperties": false + }, + "integrations": { + "type": "object", + "properties": { + "gif": { + "type": "object", + "properties": {"klipy_api_key_set": {"type": "boolean"}, "effective_available": {"type": "boolean"}}, + "required": ["klipy_api_key_set", "effective_available"], + "additionalProperties": false + }, + "youtube": { + "type": "object", + "properties": {"api_key_set": {"type": "boolean"}, "effective_available": {"type": "boolean"}}, + "required": ["api_key_set", "effective_available"], + "additionalProperties": false + }, + "captcha": { + "type": "object", + "properties": { + "provider": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/InstanceCaptchaProviderSchema"}] + }, + "effective_provider": {"$ref": "#/components/schemas/InstanceCaptchaProviderSchema"}, + "hcaptcha_site_key": {"nullable": true, "type": "string"}, + "hcaptcha_secret_key_set": {"type": "boolean"}, + "turnstile_site_key": {"nullable": true, "type": "string"}, + "turnstile_secret_key_set": {"type": "boolean"}, + "effective_enabled": {"type": "boolean"} + }, + "required": [ + "provider", + "effective_provider", + "hcaptcha_site_key", + "hcaptcha_secret_key_set", + "turnstile_site_key", + "turnstile_secret_key_set", + "effective_enabled" + ], + "additionalProperties": false + }, + "email": { + "type": "object", + "properties": { + "enabled": {"nullable": true, "type": "boolean"}, + "effective_enabled": {"type": "boolean"}, + "provider": {"nullable": true, "type": "string", "enum": ["smtp", "none"]}, + "effective_provider": {"type": "string", "enum": ["smtp", "none"]}, + "from_email": {"nullable": true, "type": "string"}, + "from_name": {"nullable": true, "type": "string"}, + "smtp": { + "type": "object", + "properties": { + "host": {"nullable": true, "type": "string"}, + "port": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 65535}, + "username": {"nullable": true, "type": "string"}, + "password_set": {"type": "boolean"}, + "secure": {"nullable": true, "type": "boolean"} + }, + "required": ["host", "port", "username", "password_set", "secure"], + "additionalProperties": false + }, + "disable_new_ip_authorization": {"type": "boolean"}, + "effective_disable_new_ip_authorization": {"type": "boolean"} + }, + "required": [ + "enabled", + "effective_enabled", + "provider", + "effective_provider", + "from_email", + "from_name", + "smtp", + "disable_new_ip_authorization", + "effective_disable_new_ip_authorization" + ], + "additionalProperties": false + }, + "bluesky": { + "type": "object", + "properties": { + "enabled": {"nullable": true, "type": "boolean"}, + "effective_enabled": {"type": "boolean"}, + "client_name": {"nullable": true, "type": "string"}, + "client_uri": {"nullable": true, "type": "string"}, + "logo_uri": {"nullable": true, "type": "string"}, + "tos_uri": {"nullable": true, "type": "string"}, + "policy_uri": {"nullable": true, "type": "string"}, + "key_count": {"type": "integer", "minimum": 0, "maximum": 9007199254740991} + }, + "required": [ + "enabled", + "effective_enabled", + "client_name", + "client_uri", + "logo_uri", + "tos_uri", + "policy_uri", + "key_count" + ], + "additionalProperties": false + } + }, + "required": ["gif", "youtube", "captcha", "email", "bluesky"], + "additionalProperties": false + }, + "media": { + "type": "object", + "properties": { + "attachment_decay": { + "type": "object", + "properties": { + "enabled": {"nullable": true, "type": "boolean"}, + "min_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, + "max_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, + "max_eligible_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, + "min_lifetime_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "max_lifetime_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "curve": {"nullable": true, "type": "number", "minimum": 0, "maximum": 1}, + "renew_threshold_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "renew_window_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "effective": { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "min_size_mb": {"type": "number", "minimum": 0, "exclusiveMinimum": true}, + "max_size_mb": {"type": "number", "minimum": 0, "exclusiveMinimum": true}, + "max_eligible_size_mb": {"type": "number", "minimum": 0, "exclusiveMinimum": true}, + "min_lifetime_days": {"type": "integer", "exclusiveMinimum": true, "maximum": 9007199254740991}, + "max_lifetime_days": {"type": "integer", "exclusiveMinimum": true, "maximum": 9007199254740991}, + "curve": {"type": "number", "minimum": 0, "maximum": 1}, + "renew_threshold_days": { + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "renew_window_days": {"type": "integer", "exclusiveMinimum": true, "maximum": 9007199254740991} + }, + "required": [ + "enabled", + "min_size_mb", + "max_size_mb", + "max_eligible_size_mb", + "min_lifetime_days", + "max_lifetime_days", + "curve", + "renew_threshold_days", + "renew_window_days" + ], + "additionalProperties": false + } + }, + "required": [ + "enabled", + "min_size_mb", + "max_size_mb", + "max_eligible_size_mb", + "min_lifetime_days", + "max_lifetime_days", + "curve", + "renew_threshold_days", + "renew_window_days", + "effective" + ], + "additionalProperties": false + } + }, + "required": ["attachment_decay"], + "additionalProperties": false + } + }, + "required": [ + "sso", + "gateway_rollout", + "voice_noise_suppression", + "experiment_delivery", + "registration", + "self_hosted", + "app_public", + "policy", + "integrations", + "media" + ], + "additionalProperties": false + }, + "CreateRegistrationUrlRequest": { + "type": "object", + "properties": { + "label": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 120}, + "expires_at": { + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "max_uses": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 1000000}, + "approval_required": {"default": false, "type": "boolean"} + } + }, + "CreateRegistrationUrlResponse": { + "type": "object", + "properties": { + "registration_url": { + "type": "object", + "properties": { + "id": {"type": "string", "minLength": 1, "maxLength": 128}, + "label": {"nullable": true, "type": "string"}, + "created_by_user_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "created_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "expires_at": { + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "max_uses": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 9007199254740991}, + "use_count": {"type": "integer", "minimum": 0, "maximum": 9007199254740991}, + "revoked_at": { + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "approval_required": {"type": "boolean"}, + "last_used_at": { + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "last_used_by_user_id": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + } + }, + "required": [ + "id", + "label", + "created_by_user_id", + "created_at", + "expires_at", + "max_uses", + "use_count", + "revoked_at", + "approval_required", + "last_used_at", + "last_used_by_user_id" + ], + "additionalProperties": false + }, + "code": {"type": "string", "minLength": 1, "maxLength": 256}, + "url": {"type": "string"} + }, + "required": ["registration_url", "code", "url"], + "additionalProperties": false + }, + "PendingRegistrationActionRequest": { + "type": "object", + "properties": { + "status": { + "description": "Pending registration decision", + "x-enumNames": ["approved", "rejected"], + "x-enumDescriptions": ["The account may log in", "The account is blocked from logging in"], + "enum": ["approved", "rejected"], + "type": "string" + } + }, + "required": ["status"] + }, + "InstanceEmailSmtpTestRequest": { + "type": "object", + "properties": { + "host": {"type": "string", "minLength": 1, "maxLength": 255}, + "port": {"type": "integer", "minimum": 1, "maximum": 65535}, + "username": {"type": "string", "minLength": 1, "maxLength": 320}, + "password": {"type": "string", "minLength": 1, "maxLength": 4096}, + "secure": {"default": true, "type": "boolean"} + }, + "required": ["host", "port", "username", "password"] + }, + "InstanceEmailSmtpTestResponse": { + "type": "object", + "properties": {"ok": {"type": "boolean"}, "error": {"nullable": true, "type": "string"}}, + "required": ["ok", "error"], + "additionalProperties": false + }, + "BrandingAssetUploadRequest": { + "type": "object", + "properties": { + "kind": {"type": "string", "enum": ["icon", "symbol", "logo", "wordmark", "favicon"]}, + "image": {"nullable": true, "type": "string", "maxLength": 16000000} + }, + "required": ["kind"] + }, + "InstanceConfigUpdateRequest": { + "type": "object", + "properties": { + "gateway_rollout": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/GatewayRolloutConfigUpdateRequest"}] + }, + "voice_noise_suppression": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/VoiceNoiseSuppressionConfigUpdateRequest"}] + }, + "experiment_delivery": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ExperimentDeliveryConfigUpdateRequest"}] + }, + "registration": { + "nullable": true, + "type": "object", + "properties": { + "mode": {"allOf": [{"$ref": "#/components/schemas/InstanceRegistrationModeSchema"}]}, + "admin_registration_urls_enabled": {"type": "boolean"} + } + }, + "sso": { + "nullable": true, + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "enforced": {"type": "boolean"}, + "display_name": {"nullable": true, "type": "string"}, + "issuer": {"nullable": true, "type": "string"}, + "authorization_url": {"nullable": true, "type": "string"}, + "token_url": {"nullable": true, "type": "string"}, + "userinfo_url": {"nullable": true, "type": "string"}, + "jwks_url": {"nullable": true, "type": "string"}, + "client_id": {"nullable": true, "type": "string"}, + "client_secret": {"nullable": true, "type": "string"}, + "scope": {"nullable": true, "type": "string"}, + "allowed_domains": {"maxItems": 100, "type": "array", "items": {"type": "string"}}, + "auto_provision": {"type": "boolean"} + } + }, + "app_public": { + "nullable": true, + "type": "object", + "properties": { + "branding": { + "nullable": true, + "type": "object", + "properties": { + "product_name": {"type": "string", "minLength": 1, "maxLength": 80}, + "icon_url": {"nullable": true, "type": "string", "maxLength": 2048}, + "symbol_url": {"nullable": true, "type": "string", "maxLength": 2048}, + "logo_url": {"nullable": true, "type": "string", "maxLength": 2048}, + "wordmark_url": {"nullable": true, "type": "string", "maxLength": 2048}, + "favicon_url": {"nullable": true, "type": "string", "maxLength": 2048}, + "theme_color": {"nullable": true, "type": "string", "maxLength": 64} + } + }, + "setup": {"nullable": true, "type": "object", "properties": {"configured": {"type": "boolean"}}}, + "legal": { + "nullable": true, + "type": "object", + "properties": { + "terms_url": {"nullable": true, "type": "string", "maxLength": 2048}, + "privacy_url": {"nullable": true, "type": "string", "maxLength": 2048} + } + }, + "registration": { + "nullable": true, + "type": "object", + "properties": {"collect_date_of_birth": {"type": "boolean"}} + } + } + }, + "integrations": { + "nullable": true, + "type": "object", + "properties": { + "gif": { + "nullable": true, + "type": "object", + "properties": {"klipy_api_key": {"nullable": true, "type": "string", "maxLength": 4096}} + }, + "youtube": { + "nullable": true, + "type": "object", + "properties": {"api_key": {"nullable": true, "type": "string", "maxLength": 4096}} + }, + "captcha": { + "nullable": true, + "type": "object", + "properties": { + "provider": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/InstanceCaptchaProviderSchema"}] + }, + "hcaptcha_site_key": {"nullable": true, "type": "string", "maxLength": 4096}, + "hcaptcha_secret_key": {"nullable": true, "type": "string", "maxLength": 4096}, + "turnstile_site_key": {"nullable": true, "type": "string", "maxLength": 4096}, + "turnstile_secret_key": {"nullable": true, "type": "string", "maxLength": 4096} + } + }, + "email": { + "nullable": true, + "type": "object", + "properties": { + "enabled": {"nullable": true, "type": "boolean"}, + "provider": {"nullable": true, "type": "string", "enum": ["smtp", "none"]}, + "from_email": {"nullable": true, "type": "string", "maxLength": 320}, + "from_name": {"nullable": true, "type": "string", "maxLength": 120}, + "smtp": { + "nullable": true, + "type": "object", + "properties": { + "host": {"nullable": true, "type": "string", "maxLength": 255}, + "port": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 65535}, + "username": {"nullable": true, "type": "string", "maxLength": 320}, + "password": {"nullable": true, "type": "string", "maxLength": 4096}, + "secure": {"nullable": true, "type": "boolean"} + } + }, + "disable_new_ip_authorization": {"nullable": true, "type": "boolean"} + } + }, + "bluesky": { + "nullable": true, + "type": "object", + "properties": { + "enabled": {"nullable": true, "type": "boolean"}, + "client_name": {"nullable": true, "type": "string", "maxLength": 120}, + "client_uri": {"nullable": true, "type": "string", "maxLength": 2048}, + "logo_uri": {"nullable": true, "type": "string", "maxLength": 2048}, + "tos_uri": {"nullable": true, "type": "string", "maxLength": 2048}, + "policy_uri": {"nullable": true, "type": "string", "maxLength": 2048}, + "keys": { + "maxItems": 8, + "type": "array", + "items": { + "type": "object", + "properties": { + "kid": {"type": "string", "minLength": 1, "maxLength": 255}, + "private_key": {"nullable": true, "type": "string", "maxLength": 10000} + }, + "required": ["kid"] + } + } + } + } + } + }, + "media": { + "nullable": true, + "type": "object", + "properties": { + "attachment_decay": { + "nullable": true, + "type": "object", + "properties": { + "enabled": {"nullable": true, "type": "boolean"}, + "min_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, + "max_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, + "max_eligible_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, + "min_lifetime_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "max_lifetime_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "curve": {"nullable": true, "type": "number", "minimum": 0, "maximum": 1}, + "renew_threshold_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + }, + "renew_window_days": { + "nullable": true, + "type": "integer", + "exclusiveMinimum": true, + "maximum": 9007199254740991 + } + } + } + } + }, + "policy": { + "nullable": true, + "type": "object", + "properties": { + "single_community_enabled": {"type": "boolean"}, + "single_community_name": {"type": "string", "minLength": 1, "maxLength": 100}, + "direct_messages_disabled": {"type": "boolean"}, + "direct_messages_locked": {"type": "boolean", "enum": [false]}, + "premium_mode": {"type": "string", "enum": ["mirror", "everyone"]}, + "services": { + "nullable": true, + "type": "object", + "properties": { + "gif_enabled": {"nullable": true, "type": "boolean"}, + "youtube_enabled": {"nullable": true, "type": "boolean"}, + "bluesky_enabled": {"nullable": true, "type": "boolean"} + } + }, + "deferred_phone_gate": { + "nullable": true, + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + "window_hours": {"type": "number", "minimum": 0, "exclusiveMinimum": true, "maximum": 8760}, + "member_threshold": {"type": "integer", "exclusiveMinimum": true, "maximum": 1000000} + } + } + } + } + } + }, + "ListGuildStickersResponse": { + "type": "object", + "properties": { + "guild_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "stickers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "name": {"type": "string", "minLength": 1, "maxLength": 100}, + "animated": {"type": "boolean"}, + "creator_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "media_url": {"type": "string", "minLength": 1, "maxLength": 2048} + }, + "required": ["id", "name", "animated", "creator_id", "media_url"], + "additionalProperties": false + } + } + }, + "required": ["guild_id", "stickers"], + "additionalProperties": false + }, + "SuccessResponse": { + "type": "object", + "properties": { + "success": {"type": "boolean", "enum": [true], "description": "Whether the operation succeeded"} + }, + "required": ["success"], + "additionalProperties": false + }, + "ListGuildMembersResponse": { + "type": "object", + "properties": { + "members": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/GuildMemberResponse"}]}}, + "total": {"$ref": "#/components/schemas/Int32Type"}, + "limit": {"$ref": "#/components/schemas/Int32Type"}, + "offset": {"$ref": "#/components/schemas/Int32Type"} + }, + "required": ["members", "total", "limit", "offset"], + "additionalProperties": false + }, + "ListGuildEmojisResponse": { + "type": "object", + "properties": { + "guild_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "emojis": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "name": {"type": "string", "minLength": 1, "maxLength": 100}, + "animated": {"type": "boolean"}, + "creator_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "media_url": {"type": "string", "minLength": 1, "maxLength": 2048} + }, + "required": ["id", "name", "animated", "creator_id", "media_url"], + "additionalProperties": false + } + } + }, + "required": ["guild_id", "emojis"], + "additionalProperties": false + }, + "BanGuildMemberBody": { + "type": "object", + "properties": { + "delete_message_days": { + "default": 0, + "description": "Number of days of messages to delete from the banned user (0-7). Deprecated in favor of delete_message_seconds.", + "type": "integer", + "minimum": 0, + "maximum": 7 + }, + "delete_message_seconds": { + "description": "Number of seconds of messages to delete for the banned user (0-604800, default 0)", + "type": "integer", + "minimum": 0, + "maximum": 604800 + }, + "reason": {"description": "The reason for the ban (max 512 characters)", "nullable": true, "type": "string"}, + "ban_duration_seconds": { + "description": "Duration of the ban in seconds (0 for permanent, or between 60 and 63072000 seconds for a temporary ban)", + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + } + }, + "AuditLogActionTypeInput": { + "description": "The type of action that occurred", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": [ + "GUILD_UPDATE", + "CHANNEL_CREATE", + "CHANNEL_UPDATE", + "CHANNEL_DELETE", + "CHANNEL_OVERWRITE_CREATE", + "CHANNEL_OVERWRITE_UPDATE", + "CHANNEL_OVERWRITE_DELETE", + "MEMBER_KICK", + "MEMBER_PRUNE", + "MEMBER_BAN_ADD", + "MEMBER_BAN_REMOVE", + "MEMBER_UPDATE", + "MEMBER_ROLE_UPDATE", + "MEMBER_MOVE", + "MEMBER_DISCONNECT", + "BOT_ADD", + "ROLE_CREATE", + "ROLE_UPDATE", + "ROLE_DELETE", + "INVITE_CREATE", + "INVITE_UPDATE", + "INVITE_DELETE", + "WEBHOOK_CREATE", + "WEBHOOK_UPDATE", + "WEBHOOK_DELETE", + "EMOJI_CREATE", + "EMOJI_UPDATE", + "EMOJI_DELETE", + "STICKER_CREATE", + "STICKER_UPDATE", + "STICKER_DELETE", + "MESSAGE_DELETE", + "MESSAGE_BULK_DELETE", + "MESSAGE_PIN", + "MESSAGE_UNPIN" + ], + "x-enumDescriptions": [ + "Guild settings were updated", + "Channel was created", + "Channel was updated", + "Channel was deleted", + "Permission overwrite was created", + "Permission overwrite was updated", + "Permission overwrite was deleted", + "Member was kicked", + "Members were pruned", + "Member was banned", + "Member ban was removed", + "Member was updated", + "Member roles were updated", + "Member was moved to a different voice channel", + "Member was disconnected from a voice channel", + "Bot was added to the guild", + "Role was created", + "Role was updated", + "Role was deleted", + "Invite was created", + "Invite was updated", + "Invite was deleted", + "Webhook was created", + "Webhook was updated", + "Webhook was deleted", + "Emoji was created", + "Emoji was updated", + "Emoji was deleted", + "Sticker was created", + "Sticker was updated", + "Sticker was deleted", + "Message was deleted", + "Messages were bulk deleted", + "Message was pinned", + "Message was unpinned" + ], + "enum": [ + 1, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 40, 41, 42, 50, 51, 52, 60, 61, 62, + 90, 91, 92, 72, 73, 74, 75 + ] + }, + "Int32Type": {"type": "integer", "minimum": 0, "maximum": 2147483647, "format": "int32"}, + "ListGuildAuditLogsResponse": { + "type": "object", + "properties": { + "audit_log_entries": { + "type": "array", + "items": {"$ref": "#/components/schemas/GuildAuditLogEntryResponse"}, + "description": "Array of audit log entries" + }, + "users": { + "type": "array", + "items": {"$ref": "#/components/schemas/UserPartialResponse"}, + "description": "Users referenced in the audit log entries" + }, + "webhooks": { + "type": "array", + "items": {"$ref": "#/components/schemas/AuditLogWebhookResponse"}, + "description": "Webhooks referenced in the audit log entries" + } + }, + "required": ["audit_log_entries", "users", "webhooks"], + "additionalProperties": false + }, + "PurgeGuildAssetsRequest": { + "type": "object", + "properties": { + "ids": { + "maxItems": 100, + "type": "array", + "items": {"type": "string"}, + "description": "List of asset IDs to purge" + } + }, + "required": ["ids"] + }, + "PurgeGuildAssetsResponseSchema": { + "type": "object", + "properties": { + "processed": {"type": "array", "items": {"$ref": "#/components/schemas/PurgeGuildAssetResultSchema"}}, + "errors": {"type": "array", "items": {"$ref": "#/components/schemas/PurgeGuildAssetErrorSchema"}} + }, + "required": ["processed", "errors"], + "additionalProperties": false + }, + "UpdateGuildRequest": { + "type": "object", + "properties": { + "verification_level": { + "description": "Required verification level for guild members", + "allOf": [{"$ref": "#/components/schemas/GuildVerificationLevelInput"}] + }, + "mfa_level": { + "description": "Required MFA level for moderators", + "allOf": [{"$ref": "#/components/schemas/GuildMFALevelInput"}] + }, + "nsfw_level": { + "description": "NSFW content level for the guild", + "allOf": [{"$ref": "#/components/schemas/NSFWLevelInput"}] + }, + "nsfw": {"description": "Whether the guild is flagged as adult content", "type": "boolean"}, + "content_warning_level": { + "description": "Content warning level for the guild", + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevelInput"}] + }, + "content_warning_text": { + "description": "Custom content warning text shown before entry", + "nullable": true, + "type": "string" + }, + "explicit_content_filter": { + "description": "Explicit content filter level", + "allOf": [{"$ref": "#/components/schemas/GuildExplicitContentFilterInput"}] + }, + "default_message_notifications": { + "description": "Default notification setting for new members", + "allOf": [{"$ref": "#/components/schemas/DefaultMessageNotificationsInput"}] + }, + "disabled_operations": {"allOf": [{"$ref": "#/components/schemas/GuildOperations"}]}, + "name": {"description": "New name for the guild", "type": "string"}, + "vanity_url_code": { + "nullable": true, + "description": "New vanity URL code, or null to remove", + "type": "string" + }, + "new_owner_id": { + "description": "ID of the user to transfer ownership to", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "add_features": { + "maxItems": 100, + "type": "array", + "items": {"allOf": [{"$ref": "#/components/schemas/GuildFeatureSchema"}]} + }, + "remove_features": { + "maxItems": 100, + "type": "array", + "items": {"allOf": [{"$ref": "#/components/schemas/GuildFeatureSchema"}]} + }, + "fields": { + "maxItems": 10, + "type": "array", + "items": { + "description": "Guild image field that can be cleared", + "x-enumNames": ["icon", "banner", "splash", "embed_splash"], + "x-enumDescriptions": [ + "Guild icon image", + "Guild banner image", + "Guild invite splash image", + "Guild embedded invite splash image" + ], + "enum": ["icon", "banner", "splash", "embed_splash"], + "type": "string" + }, + "description": "List of guild image fields to clear" + } + } + }, + "GuildUpdateResponse": { + "type": "object", + "properties": { + "guild": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "name": {"type": "string", "minLength": 1, "maxLength": 100}, + "features": { + "maxItems": 100, + "type": "array", + "items": {"type": "string", "minLength": 1, "maxLength": 256} + }, + "owner_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "icon": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "banner": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "member_count": {"$ref": "#/components/schemas/Int32Type"}, + "nsfw_level": {"allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "nsfw": {"type": "boolean"}, + "content_warning_level": {"allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}]}, + "content_warning_text": {"nullable": true, "type": "string", "maxLength": 200} + }, + "required": ["id", "name", "features", "owner_id", "icon", "banner", "member_count"], + "additionalProperties": false + } + }, + "required": ["guild"], + "additionalProperties": false + }, + "LookupGuildResponse": { + "type": "object", + "properties": { + "guild": { + "nullable": true, + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "owner_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "owner_username": {"nullable": true, "type": "string"}, + "owner_global_name": {"nullable": true, "type": "string"}, + "owner_discriminator": {"nullable": true, "type": "string"}, + "name": {"type": "string", "minLength": 1, "maxLength": 100}, + "vanity_url_code": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "icon": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "banner": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "splash": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "embed_splash": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "features": { + "maxItems": 100, + "type": "array", + "items": {"type": "string", "minLength": 1, "maxLength": 256} + }, + "verification_level": {"allOf": [{"$ref": "#/components/schemas/GuildVerificationLevel"}]}, + "mfa_level": {"allOf": [{"$ref": "#/components/schemas/GuildMFALevel"}]}, + "nsfw_level": {"allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "nsfw": {"type": "boolean"}, + "content_warning_level": {"allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}]}, + "content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "explicit_content_filter": {"allOf": [{"$ref": "#/components/schemas/GuildExplicitContentFilter"}]}, + "default_message_notifications": { + "allOf": [{"$ref": "#/components/schemas/DefaultMessageNotifications"}] + }, + "afk_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "afk_timeout": {"$ref": "#/components/schemas/Int32Type"}, + "system_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "system_channel_flags": {"allOf": [{"$ref": "#/components/schemas/SystemChannelFlags"}]}, + "rules_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "disabled_operations": {"$ref": "#/components/schemas/Int32Type"}, + "member_count": {"$ref": "#/components/schemas/Int32Type"}, + "channels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "name": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 100}, + "type": {"allOf": [{"$ref": "#/components/schemas/ChannelType"}]}, + "position": {"$ref": "#/components/schemas/Int32Type"}, + "parent_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "nsfw": {"nullable": true, "type": "boolean"}, + "nsfw_override": {"nullable": true, "type": "boolean"}, + "content_warning_level": {"allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}]}, + "content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "url": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 2048} + }, + "required": ["id", "name", "type", "position", "parent_id", "nsfw", "url"], + "additionalProperties": false + } + }, + "roles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "name": {"type": "string", "minLength": 1, "maxLength": 100}, + "color": {"$ref": "#/components/schemas/Int32Type"}, + "position": {"$ref": "#/components/schemas/Int32Type"}, + "permissions": { + "description": "The role permissions bitfield", + "allOf": [{"$ref": "#/components/schemas/Permissions"}] + }, + "hoist": {"type": "boolean"}, + "mentionable": {"type": "boolean"} + }, + "required": ["id", "name", "color", "position", "permissions", "hoist", "mentionable"], + "additionalProperties": false + } + } + }, + "required": [ + "id", + "owner_id", + "owner_username", + "owner_global_name", + "owner_discriminator", + "name", + "vanity_url_code", + "icon", + "banner", + "splash", + "embed_splash", + "features", + "verification_level", + "mfa_level", + "nsfw_level", + "explicit_content_filter", + "default_message_notifications", + "afk_channel_id", + "afk_timeout", + "system_channel_id", + "system_channel_flags", + "rules_channel_id", + "disabled_operations", + "member_count", + "channels", + "roles" + ], + "additionalProperties": false + } + }, + "required": ["guild"], + "additionalProperties": false + }, + "SearchGuildsResponse": { + "type": "object", + "properties": { + "guilds": {"type": "array", "items": {"$ref": "#/components/schemas/GuildAdminResponse"}}, + "total": {"type": "number"} + }, + "required": ["guilds", "total"], + "additionalProperties": false + }, + "GenerateGiftCodesRequest": { + "type": "object", + "properties": { + "count": {"type": "integer", "minimum": 1, "maximum": 100, "description": "Number of gift codes to generate"}, + "duration_type": { + "description": "Duration unit for the generated gift codes", + "allOf": [{"$ref": "#/components/schemas/GiftCodeDurationTypeSchema"}] + }, + "duration_quantity": { + "type": "integer", + "minimum": 1, + "maximum": 3650, + "description": "Duration quantity for the selected unit. Lifetime gifts are not supported." + } + }, + "required": ["count", "duration_type", "duration_quantity"] + }, + "CodesResponse": { + "type": "object", + "properties": {"codes": {"type": "array", "items": {"type": "string"}}}, + "required": ["codes"], + "additionalProperties": false + }, + "GatewayVoiceStateCountsResponse": { + "type": "object", + "properties": { + "total_voice_states": {"$ref": "#/components/schemas/Int32Type"}, + "regions": { + "maxItems": 1000, + "type": "array", + "items": { + "type": "object", + "properties": { + "region_id": {"type": "string", "minLength": 1, "maxLength": 64}, + "voice_state_count": {"$ref": "#/components/schemas/Int32Type"} + }, + "required": ["region_id", "voice_state_count"], + "additionalProperties": false + } + }, + "servers": { + "maxItems": 5000, + "type": "array", + "items": { + "type": "object", + "properties": { + "server_id": {"type": "string", "minLength": 1, "maxLength": 128}, + "voice_state_count": {"$ref": "#/components/schemas/Int32Type"} + }, + "required": ["server_id", "voice_state_count"], + "additionalProperties": false + } + } + }, + "required": ["total_voice_states", "regions", "servers"], + "additionalProperties": false + }, + "NodeStatsResponse": { + "type": "object", + "properties": { + "status": {"type": "string", "minLength": 1, "maxLength": 256}, + "sessions": {"$ref": "#/components/schemas/Int32Type"}, + "guilds": {"$ref": "#/components/schemas/Int32Type"}, + "presences": {"$ref": "#/components/schemas/Int32Type"}, + "calls": {"$ref": "#/components/schemas/Int32Type"}, + "memory": { + "type": "object", + "properties": { + "total": {"$ref": "#/components/schemas/Int64StringType"}, + "processes": {"$ref": "#/components/schemas/Int64StringType"}, + "system": {"$ref": "#/components/schemas/Int64StringType"} + }, + "required": ["total", "processes", "system"], + "additionalProperties": false + }, + "process_count": {"$ref": "#/components/schemas/Int32Type"}, + "process_limit": {"$ref": "#/components/schemas/Int32Type"}, + "uptime_seconds": {"$ref": "#/components/schemas/Int32Type"}, + "node_count": {"$ref": "#/components/schemas/Int32Type"}, + "nodes": { + "maxItems": 1000, + "type": "array", + "items": { + "type": "object", + "properties": { + "node_id": {"type": "string", "minLength": 1, "maxLength": 256}, + "status": {"type": "string", "minLength": 1, "maxLength": 256}, + "sessions": {"$ref": "#/components/schemas/Int32Type"}, + "guilds": {"$ref": "#/components/schemas/Int32Type"}, + "presences": {"$ref": "#/components/schemas/Int32Type"}, + "calls": {"$ref": "#/components/schemas/Int32Type"}, + "memory": { + "type": "object", + "properties": { + "total": {"$ref": "#/components/schemas/Int64StringType"}, + "processes": {"$ref": "#/components/schemas/Int64StringType"}, + "system": {"$ref": "#/components/schemas/Int64StringType"} + }, + "required": ["total", "processes", "system"], + "additionalProperties": false + }, + "process_count": {"$ref": "#/components/schemas/Int32Type"}, + "process_limit": {"$ref": "#/components/schemas/Int32Type"}, + "uptime_seconds": {"$ref": "#/components/schemas/Int32Type"} + }, + "required": [ + "node_id", + "status", + "sessions", + "guilds", + "presences", + "calls", + "memory", + "process_count", + "process_limit", + "uptime_seconds" + ], + "additionalProperties": false + } + } + }, + "required": [ + "status", + "sessions", + "guilds", + "presences", + "calls", + "memory", + "process_count", + "process_limit", + "uptime_seconds", + "node_count", + "nodes" + ], + "additionalProperties": false + }, + "ReloadGuildsRequest": { + "type": "object", + "properties": { + "guild_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "List of guild IDs to reload" + } + }, + "required": ["guild_ids"] + }, + "ReloadAllGuildsResponse": { + "type": "object", + "properties": {"count": {"$ref": "#/components/schemas/Int32Type"}}, + "required": ["count"], + "additionalProperties": false + }, + "GuildMemoryStatsResponse": { + "type": "object", + "properties": { + "guilds": { + "maxItems": 1000, + "type": "array", + "items": { + "type": "object", + "properties": { + "node_id": {"type": "string", "minLength": 1, "maxLength": 256}, + "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "guild_name": {"type": "string", "minLength": 1, "maxLength": 100}, + "guild_icon": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "memory": {"$ref": "#/components/schemas/Int64StringType"}, + "member_count": {"$ref": "#/components/schemas/Int32Type"}, + "session_count": {"$ref": "#/components/schemas/Int32Type"}, + "presence_count": {"$ref": "#/components/schemas/Int32Type"} + }, + "required": [ + "node_id", + "guild_id", + "guild_name", + "guild_icon", + "nsfw_level", + "memory", + "member_count", + "session_count", + "presence_count" + ], + "additionalProperties": false + } + } + }, + "required": ["guilds"], + "additionalProperties": false + }, + "DiscoveryAdminRemoveRequest": { + "type": "object", + "properties": {"reason": {"type": "string", "minLength": 1, "maxLength": 500, "description": "Removal reason"}}, + "required": ["reason"] + }, + "DiscoveryApplicationResponse": { + "type": "object", + "properties": { + "guild_id": {"description": "Guild ID", "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "guild_nsfw_level": { + "description": "NSFW level of the guild", + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}] + }, + "status": {"type": "string", "description": "Application status"}, + "description": {"type": "string", "description": "Discovery description"}, + "category_type": {"type": "number", "description": "Discovery category type"}, + "primary_language": {"description": "Primary community language", "nullable": true, "type": "string"}, + "custom_tags": {"type": "array", "items": {"type": "string"}, "description": "Custom discovery tags"}, + "applied_at": {"type": "string", "description": "Application timestamp"}, + "reviewed_at": {"description": "Review timestamp", "nullable": true, "type": "string"}, + "review_reason": {"description": "Review reason (approval/rejection)", "nullable": true, "type": "string"}, + "removed_at": {"description": "Removal timestamp", "nullable": true, "type": "string"}, + "removal_reason": {"description": "Removal reason", "nullable": true, "type": "string"} + }, + "required": ["guild_id", "status", "description", "category_type", "custom_tags", "applied_at"], + "additionalProperties": false + }, + "DiscoveryApplicationPatchRequest": { + "type": "object", + "properties": { + "description": { + "description": "Updated description for discovery listing", + "type": "string", + "minLength": 10, + "maxLength": 300 + }, + "category_type": { + "description": "Updated discovery category type", + "type": "integer", + "minimum": 0, + "maximum": 8 + }, + "primary_language": {"type": "string", "description": "Primary community language (BCP-47 code)"}, + "custom_tags": { + "maxItems": 10, + "type": "array", + "items": {"type": "string", "minLength": 2, "maxLength": 30}, + "description": "Up to 10 custom discovery tags" + } + } + }, + "DiscoveryAdminListingBulkCategoryRequest": { + "type": "object", + "properties": { + "guild_ids": { + "minItems": 1, + "maxItems": 100, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "Listed guilds to move" + }, + "category_type": { + "type": "integer", + "minimum": 0, + "maximum": 8, + "description": "Discovery category to file every named guild under" + } + }, + "required": ["guild_ids", "category_type"] + }, + "DiscoveryAdminListingBulkCategoryResponse": { + "type": "object", + "properties": { + "updated": {"type": "number", "description": "Number of listings moved"}, + "failed_guild_ids": { + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "description": "Guilds that could not be moved" + } + }, + "required": ["updated", "failed_guild_ids"], + "additionalProperties": false + }, + "DiscoveryAdminListedGuildListResponse": { + "type": "array", + "items": {"$ref": "#/components/schemas/DiscoveryAdminListedGuildResponse"} + }, + "DiscoveryCategoryListResponse": { + "type": "array", + "items": {"$ref": "#/components/schemas/DiscoveryCategoryResponse"} + }, + "DiscoveryAdminApplicationUpdateRequest": { + "oneOf": [ + { + "type": "object", + "properties": { + "reason": {"allOf": [{"$ref": "#/components/schemas/DiscoveryReviewReason"}]}, + "status": {"type": "string", "enum": ["approved"], "description": "Approve the pending application"} + }, + "required": ["status"] + }, + { + "type": "object", + "properties": { + "reason": {"allOf": [{"$ref": "#/components/schemas/DiscoveryRejectionReason"}]}, + "status": {"type": "string", "enum": ["rejected"], "description": "Reject the pending application"} + }, + "required": ["reason", "status"] + } + ] + }, + "DiscoveryAdminPendingApplicationListResponse": { + "type": "array", + "items": {"$ref": "#/components/schemas/DiscoveryAdminPendingApplicationResponse"} + }, + "DeleteMessageResponse": { + "type": "object", + "properties": {"success": {"type": "boolean", "enum": [true]}}, + "required": ["success"], + "additionalProperties": false + }, + "LookupMessageResponse": { + "type": "object", + "properties": { + "messages": {"maxItems": 100, "type": "array", "items": {"$ref": "#/components/schemas/AdminMessageSchema"}}, + "message_responses": { + "maxItems": 100, + "type": "array", + "items": {"$ref": "#/components/schemas/MessageResponseSchema"} + }, + "message_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]} + }, + "required": ["messages", "message_id"], + "additionalProperties": false + }, + "BrowseChannelResponse": { + "type": "object", + "properties": { + "messages": {"maxItems": 100, "type": "array", "items": {"$ref": "#/components/schemas/AdminMessageSchema"}}, + "message_responses": { + "maxItems": 100, + "type": "array", + "items": {"$ref": "#/components/schemas/MessageResponseSchema"} + }, + "has_more": {"type": "boolean"} + }, + "required": ["messages", "has_more"], + "additionalProperties": false + }, + "AdminBulkJobCreateRequest": { + "oneOf": [ + { + "type": "object", + "properties": { + "user_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "List of user IDs to update" + }, + "add_flags": { + "default": [], + "description": "User flags to add to all specified users", + "maxItems": 64, + "type": "array", + "items": { + "description": "A single user flag value to add or remove", + "allOf": [{"$ref": "#/components/schemas/UserFlags"}] + } + }, + "remove_flags": { + "default": [], + "description": "User flags to remove from all specified users", + "maxItems": 64, + "type": "array", + "items": { + "description": "A single user flag value to add or remove", + "allOf": [{"$ref": "#/components/schemas/UserFlags"}] + } + }, + "task": { + "type": "string", + "enum": ["update_user_flags"], + "description": "Adds and removes account flags on every targeted user" + } + }, + "required": ["user_ids", "task"] + }, + { + "type": "object", + "properties": { + "user_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "List of user IDs to update" + }, + "add_flags": { + "default": [], + "description": "Suspicious activity flag names to add to all specified users", + "maxItems": 32, + "type": "array", + "items": {"type": "string"} + }, + "remove_flags": { + "default": [], + "description": "Suspicious activity flag names to remove from all specified users", + "maxItems": 32, + "type": "array", + "items": {"type": "string"} + }, + "task": { + "type": "string", + "enum": ["update_suspicious_activity_flags"], + "description": "Adds and removes verification requirements on every targeted user" + } + }, + "required": ["user_ids", "task"] + }, + { + "type": "object", + "properties": { + "guild_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "List of guild IDs to update" + }, + "add_features": { + "default": [], + "description": "Guild features to add to all specified guilds", + "maxItems": 100, + "type": "array", + "items": {"allOf": [{"$ref": "#/components/schemas/GuildFeatureSchema"}]} + }, + "remove_features": { + "default": [], + "description": "Guild features to remove from all specified guilds", + "maxItems": 100, + "type": "array", + "items": {"allOf": [{"$ref": "#/components/schemas/GuildFeatureSchema"}]} + }, + "task": { + "type": "string", + "enum": ["update_guild_features"], + "description": "Adds and removes features on every targeted guild" + } + }, + "required": ["guild_ids", "task"] + }, + { + "type": "object", + "properties": { + "guild_id": { + "description": "ID of the guild to add members to", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + }, + "user_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "List of user IDs to add as members" + }, + "task": { + "type": "string", + "enum": ["add_guild_members"], + "description": "Adds every targeted user to one guild" + } + }, + "required": ["guild_id", "user_ids", "task"] + }, + { + "type": "object", + "properties": { + "reason_code": { + "description": "Code indicating the reason for deletion", + "allOf": [{"$ref": "#/components/schemas/DeletionReasonCode"}] + }, + "public_reason": {"description": "Public-facing reason for the deletion", "type": "string"}, + "days_until_deletion": { + "default": 60, + "description": "Number of days until the accounts are deleted", + "type": "integer", + "minimum": 1, + "maximum": 365 + }, + "user_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "List of user IDs to schedule deletion for" + }, + "task": { + "type": "string", + "enum": ["schedule_user_deletion"], + "description": "Schedules account deletion for every targeted user" + } + }, + "required": ["reason_code", "user_ids", "task"] + }, + { + "type": "object", + "properties": { + "user_ids": { + "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeType"}, + "description": "List of user IDs whose messages will be deleted" + }, + "task": { + "type": "string", + "enum": ["delete_user_messages"], + "description": "Deletes every message authored by each targeted user, across all channels" + } + }, + "required": ["user_ids", "task"] + } + ] + }, + "BulkJobResponse": { + "type": "object", + "properties": {"job_id": {"$ref": "#/components/schemas/SnowflakeStringType"}}, + "required": ["job_id"], + "additionalProperties": false + }, + "AdminBlocklistListType": { + "type": "string", + "enum": [ + "ip", + "email", + "email-domain-suspicious", + "phrase", + "url", + "url-domain", + "file-sha", + "avatar-hash", + "profile-substring" + ], + "description": "The blocklist an entry belongs to" + }, + "AdminBlocklistEntryUpdateRequest": { + "anyOf": [ + {"$ref": "#/components/schemas/AdminBlocklistUrlUpdateRequest"}, + {"$ref": "#/components/schemas/AdminBlocklistUrlDomainUpdateRequest"}, + {"$ref": "#/components/schemas/AdminBlocklistFileShaUpdateRequest"}, + {"$ref": "#/components/schemas/AdminBlocklistAvatarHashUpdateRequest"}, + {"$ref": "#/components/schemas/AdminBlocklistProfileSubstringUpdateRequest"} + ], + "description": "The stored fields to write, in the shape the blocklist named by list_type accepts" + }, + "BanCheckResponseSchema": { + "type": "object", + "properties": {"banned": {"type": "boolean"}}, + "required": ["banned"], + "additionalProperties": false + }, + "AdminBlocklistBulkDeleteRequest": { + "anyOf": [ + {"$ref": "#/components/schemas/CheckAvatarHashRequest"}, + {"$ref": "#/components/schemas/BanProfileSubstringRequest"} + ], + "description": "The entries to remove, in the shape the blocklist named by list_type accepts" + }, + "BulkBanFileShasRequest": { + "type": "object", + "properties": { + "sha256_list": { + "minItems": 1, + "maxItems": 10000, + "type": "array", + "items": {"type": "string"}, + "description": "Array of SHA-256 hex strings to ban" + } + }, + "required": ["sha256_list"] + }, + "AdminBlocklistEntryCreateRequest": { + "anyOf": [ + {"$ref": "#/components/schemas/BanIpRequest"}, + {"$ref": "#/components/schemas/BanEmailRequest"}, + {"$ref": "#/components/schemas/SuspiciousEmailDomainRequest"}, + {"$ref": "#/components/schemas/BanPhraseRequest"}, + {"$ref": "#/components/schemas/BanUrlRequest"}, + {"$ref": "#/components/schemas/BanUrlDomainRequest"}, + {"$ref": "#/components/schemas/BanFileShaRequest"}, + {"$ref": "#/components/schemas/BanAvatarHashRequest"}, + {"$ref": "#/components/schemas/BanProfileSubstringRequest"} + ], + "description": "The entry to add, in the shape the blocklist named by list_type accepts" + }, + "AdminBlocklistEntryListResponse": { + "type": "object", + "properties": { + "items": { + "maxItems": 200, + "type": "array", + "items": { + "type": "object", + "properties": { + "list_type": {"allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}]}, + "value": { + "description": "The canonical stored value of the entry", + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "scope": { + "nullable": true, + "description": "The profile field the entry is scoped to, or null when the blocklist is unscoped", + "type": "string" + }, + "category": { + "nullable": true, + "description": "The category slug stored alongside the entry, or null", + "type": "string" + }, + "severity": { + "nullable": true, + "description": "The stored severity, or null when the blocklist has no severity", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "source_url": { + "nullable": true, + "description": "The upstream source the entry was imported from, or null", + "type": "string" + }, + "notes": { + "nullable": true, + "description": "The internal notes stored alongside the entry, or null", + "type": "string" + }, + "content_type": { + "nullable": true, + "description": "The MIME type hint stored alongside the entry, or null", + "type": "string" + }, + "match_subdomains": { + "nullable": true, + "description": "Whether subdomains are covered by the entry, or null when the blocklist has no such flag", + "type": "boolean" + }, + "reason": { + "nullable": true, + "description": "The stored reason for the entry, or null", + "type": "string" + }, + "expires_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the entry expires, or null", + "type": "string" + }, + "created_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the entry was added, or null", + "type": "string" + }, + "created_by_user_id": { + "nullable": true, + "description": "The admin who added the entry, or null when unknown", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + } + }, + "required": [ + "list_type", + "value", + "scope", + "category", + "severity", + "source_url", + "notes", + "content_type", + "match_subdomains", + "reason", + "expires_at", + "created_at", + "created_by_user_id" + ], + "additionalProperties": false + }, + "description": "The blocklist entries in this page, ordered by value" + }, + "has_more": { + "type": "boolean", + "description": "Whether another page can be fetched with the next_after cursor" + }, + "next_after": { + "nullable": true, + "description": "Cursor to send as after on the next request, or null when this is the last page", + "type": "string" + } + }, + "required": ["items", "has_more", "next_after"], + "additionalProperties": false + }, + "AdminBlocklistTypeListResponse": { + "type": "object", + "properties": { + "items": { + "maxItems": 50, + "type": "array", + "items": { + "type": "object", + "properties": { + "list_type": {"allOf": [{"$ref": "#/components/schemas/AdminBlocklistListType"}]}, + "description": { + "type": "string", + "description": "What the blocklist matches and how matching is performed" + }, + "value_field": { + "type": "string", + "description": "The request body field that carries the entry value when adding to this blocklist" + }, + "fields": { + "maxItems": 8, + "type": "array", + "items": {"type": "string"}, + "description": "Fields entries of this blocklist accept beyond the value itself" + }, + "scoped": { + "type": "boolean", + "description": "Whether entries are scoped to a profile field and a scope must be supplied" + }, + "supports_bulk_create": { + "type": "boolean", + "description": "Whether PUT on the entry collection is accepted" + }, + "supports_bulk_delete": { + "type": "boolean", + "description": "Whether DELETE on the entry collection is accepted" + }, + "supports_update": {"type": "boolean", "description": "Whether PATCH on a single entry is accepted"} + }, + "required": [ + "list_type", + "description", + "value_field", + "fields", + "scoped", + "supports_bulk_create", + "supports_bulk_delete", + "supports_update" + ], + "additionalProperties": false + }, + "description": "Every blocklist exposed by this instance" + } + }, + "required": ["items"], + "additionalProperties": false + }, + "AdminAuditLogResponseSchema": { + "type": "object", + "properties": { + "log_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "admin_user_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "admin_user": { + "nullable": true, + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "username": {"type": "string"}, + "discriminator": {"type": "string"}, + "global_name": {"nullable": true, "type": "string"} + }, + "required": ["id", "username", "discriminator", "global_name"], + "additionalProperties": false + }, + "target_type": {"type": "string", "minLength": 1, "maxLength": 256}, + "target_id": { + "type": "string", + "description": "The ID of the affected entity (user, channel, role, invite code, etc.)" + }, + "target_user": { + "nullable": true, + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "username": {"type": "string"}, + "discriminator": {"type": "string"}, + "global_name": {"nullable": true, "type": "string"} + }, + "required": ["id", "username", "discriminator", "global_name"], + "additionalProperties": false + }, + "target_guild": { + "nullable": true, + "type": "object", + "properties": {"id": {"$ref": "#/components/schemas/SnowflakeStringType"}, "name": {"type": "string"}}, + "required": ["id", "name"], + "additionalProperties": false + }, + "target_channel": { + "nullable": true, + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "name": {"nullable": true, "type": "string"}, + "type": {"allOf": [{"$ref": "#/components/schemas/ChannelType"}]}, + "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]} + }, + "required": ["id", "name", "type", "guild_id"], + "additionalProperties": false + }, + "related_users": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "username": {"type": "string"}, + "discriminator": {"type": "string"}, + "global_name": {"nullable": true, "type": "string"} + }, + "required": ["id", "username", "discriminator", "global_name"], + "additionalProperties": false + } + }, + "related_guilds": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {"id": {"$ref": "#/components/schemas/SnowflakeStringType"}, "name": {"type": "string"}}, + "required": ["id", "name"], + "additionalProperties": false + } + }, + "related_channels": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "name": {"nullable": true, "type": "string"}, + "type": {"allOf": [{"$ref": "#/components/schemas/ChannelType"}]}, + "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]} + }, + "required": ["id", "name", "type", "guild_id"], + "additionalProperties": false + } + }, + "action": {"type": "string", "minLength": 1, "maxLength": 256}, + "audit_log_reason": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 4000}, + "metadata": {"type": "object", "additionalProperties": {"type": "string", "maxLength": 4000}}, + "created_at": {"type": "string"} + }, + "required": [ + "log_id", + "admin_user_id", + "admin_user", + "target_type", + "target_id", + "target_user", + "target_guild", + "target_channel", + "related_users", + "related_guilds", + "related_channels", + "action", + "audit_log_reason", + "metadata", + "created_at" + ], + "additionalProperties": false + }, + "AuditLogsListResponseSchema": { + "type": "object", + "properties": { + "logs": {"type": "array", "items": {"$ref": "#/components/schemas/AdminAuditLogResponseSchema"}}, + "total": {"type": "number"} + }, + "required": ["logs", "total"], + "additionalProperties": false + }, + "ArchiveSubjectTypeSchema": { + "description": "Type of subject being archived", + "x-enumNames": ["user", "guild"], + "x-enumDescriptions": ["User data archive", "Guild data archive"], + "enum": ["user", "guild"], + "type": "string" + }, + "DownloadUrlResponseSchema": { + "type": "object", + "properties": { + "downloadUrl": {"type": "string", "minLength": 1, "maxLength": 2048}, + "expiresAt": {"type": "string"} + }, + "required": ["downloadUrl", "expiresAt"], + "additionalProperties": false + }, + "GetArchiveResponseSchema": { + "type": "object", + "properties": { + "archive": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/AdminArchiveResponseSchema"}]} + }, + "required": ["archive"], + "additionalProperties": false + }, + "ListArchivesResponseSchema": { + "type": "object", + "properties": { + "archives": {"type": "array", "items": {"$ref": "#/components/schemas/AdminArchiveResponseSchema"}} + }, + "required": ["archives"], + "additionalProperties": false + }, + "TransferApplicationOwnershipRequest": { + "type": "object", + "properties": { + "new_owner_id": { + "description": "ID of the user to transfer ownership to", + "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + } + }, + "required": ["new_owner_id"] + }, + "ApplicationUpdateResponse": { + "type": "object", + "properties": {"application": {"$ref": "#/components/schemas/ApplicationAdminResponse"}}, + "required": ["application"], + "additionalProperties": false + }, + "LookupApplicationResponse": { + "type": "object", + "properties": { + "application": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/ApplicationAdminResponse"}]} + }, + "required": ["application"], + "additionalProperties": false + }, + "DeleteApiKeyResponse": { + "type": "object", + "properties": {"success": {"type": "boolean", "enum": [true]}}, + "required": ["success"], + "additionalProperties": false + }, + "UpdateAdminApiKeyRequest": { + "type": "object", + "properties": { + "name": { + "description": "New display name for the API key", + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "acls": { + "description": "Replacement list of access control permissions for the key", + "maxItems": 112, + "type": "array", + "items": {"$ref": "#/components/schemas/AdminAclType"} + } + } + }, + "ListAdminApiKeyResponse": { + "type": "object", + "properties": { + "key_id": {"type": "string", "description": "Unique identifier for the API key"}, + "name": {"type": "string", "description": "Display name for the API key"}, + "created_at": {"type": "string", "description": "ISO 8601 timestamp when the key was created"}, + "expires_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the key expires, or null if no expiration", + "type": "string" + }, + "acls": { + "maxItems": 112, + "type": "array", + "items": {"type": "string"}, + "description": "List of access control permissions for the key" + }, + "last_used_at": { + "nullable": true, + "description": "ISO 8601 timestamp when the key was last used, or null if never used", + "type": "string" + }, + "created_by_user_id": { + "description": "User ID of the admin who created this key", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + } + }, + "required": ["key_id", "name", "created_at", "expires_at", "acls", "last_used_at", "created_by_user_id"], + "additionalProperties": false + }, + "AdminApiKeyListResponse": {"type": "array", "items": {"$ref": "#/components/schemas/ListAdminApiKeyResponse"}}, + "CreateAdminApiKeyRequest": { + "type": "object", + "properties": { + "name": {"type": "string", "minLength": 1, "maxLength": 100, "description": "Display name for the API key"}, + "expires_in_days": { + "description": "Number of days until the key expires", + "type": "integer", + "minimum": 1, + "maximum": 365 + }, + "acls": { + "maxItems": 112, + "type": "array", + "items": {"$ref": "#/components/schemas/AdminAclType"}, + "description": "List of access control permissions for the key" + } + }, + "required": ["name", "acls"] }, "CreateAdminApiKeyResponse": { "type": "object", @@ -8745,40 +12758,35 @@ "name": {"type": "string", "description": "Display name for the API key"}, "created_at": {"type": "string", "description": "ISO 8601 timestamp when the key was created"}, "expires_at": { - "description": "ISO 8601 timestamp when the key expires, or null if no expiration", "nullable": true, + "description": "ISO 8601 timestamp when the key expires, or null if no expiration", "type": "string" }, "acls": { + "maxItems": 112, "type": "array", "items": {"type": "string"}, - "maxItems": 112, "description": "List of access control permissions for the key" } }, - "required": ["key_id", "key", "name", "created_at", "expires_at", "acls"] + "required": ["key_id", "key", "name", "created_at", "expires_at", "acls"], + "additionalProperties": false }, - "CreateAdminApiKeyRequest": { + "AdminAclListResponse": { "type": "object", "properties": { - "name": {"type": "string", "minLength": 1, "maxLength": 100, "description": "Display name for the API key"}, - "expires_in_days": { - "type": "integer", - "minimum": 1, - "maximum": 365, - "format": "int32", - "description": "Number of days until the key expires" - }, "acls": { - "type": "array", - "items": {"$ref": "#/components/schemas/AdminAclType"}, "maxItems": 112, - "description": "List of access control permissions for the key" + "type": "array", + "items": {"type": "string", "minLength": 1, "maxLength": 64}, + "description": "Every admin access control permission the admin API recognises" } }, - "required": ["name", "acls"] + "required": ["acls"], + "additionalProperties": false }, "AdminAclType": { + "type": "string", "enum": [ "*", "acl:set:user", @@ -8892,112 +12900,54 @@ "voice:server:delete", "voice:server:list", "voice:server:update" - ], - "type": "string" - }, - "ListAdminApiKeyResponse": { - "type": "object", - "properties": { - "key_id": {"type": "string", "description": "Unique identifier for the API key"}, - "name": {"type": "string", "description": "Display name for the API key"}, - "created_at": {"type": "string", "description": "ISO 8601 timestamp when the key was created"}, - "last_used_at": { - "description": "ISO 8601 timestamp when the key was last used, or null if never used", - "nullable": true, - "type": "string" - }, - "expires_at": { - "description": "ISO 8601 timestamp when the key expires, or null if no expiration", - "nullable": true, - "type": "string" - }, - "created_by_user_id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "User ID of the admin who created this key" - }, - "acls": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 112, - "description": "List of access control permissions for the key" - } - }, - "required": ["key_id", "name", "created_at", "last_used_at", "expires_at", "created_by_user_id", "acls"] - }, - "SnowflakeType": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "format": "snowflake"}, - "UpdateAdminApiKeyRequest": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "maxLength": 100, - "description": "New display name for the API key" - }, - "acls": { - "type": "array", - "items": {"$ref": "#/components/schemas/AdminAclType"}, - "maxItems": 112, - "description": "Replacement list of access control permissions for the key" - } - } - }, - "DeleteApiKeyResponse": { - "type": "object", - "properties": {"success": {"type": "boolean", "enum": [true]}}, - "required": ["success"] - }, - "ListApplicationsResponse": { - "type": "object", - "properties": { - "applications": {"type": "array", "items": {"$ref": "#/components/schemas/ApplicationAdminResponse"}} - }, - "required": ["applications"] + ] }, "ApplicationAdminResponse": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier for this application" + "description": "The unique identifier for this application", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "name": {"type": "string", "description": "The display name of the application"}, - "owner_user_id": { + "name": { + "description": "The display name of the application", "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The user ID that owns this application" + "minLength": 1, + "maxLength": 256 + }, + "owner_user_id": { + "description": "The user ID that owns this application", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "owner_username": { - "description": "The username of the owner, if resolvable", "nullable": true, + "description": "The username of the owner, if resolvable", "type": "string" }, "owner_global_name": { - "description": "The display name of the owner, if set", "nullable": true, + "description": "The display name of the owner, if set", "type": "string" }, "owner_discriminator": { - "description": "The discriminator of the owner, if resolvable", "nullable": true, + "description": "The discriminator of the owner, if resolvable", "type": "string" }, "bot_user_id": { + "nullable": true, "description": "The user ID of the associated bot user, if any", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "bot_username": {"description": "The username of the bot user, if any", "nullable": true, "type": "string"}, + "bot_username": {"nullable": true, "description": "The username of the bot user, if any", "type": "string"}, "bot_global_name": { - "description": "The display name of the bot user, if set", "nullable": true, + "description": "The display name of the bot user, if set", "type": "string" }, "bot_discriminator": { - "description": "The discriminator of the bot user, if any", "nullable": true, + "description": "The discriminator of the bot user, if any", "type": "string" }, "bot_is_public": {"type": "boolean", "description": "Whether the bot is publicly joinable"}, @@ -9006,9 +12956,9 @@ "description": "Whether an OAuth2 code grant is required for this bot" }, "oauth2_redirect_uris": { + "maxItems": 10, "type": "array", "items": {"type": "string"}, - "maxItems": 10, "description": "Registered OAuth2 redirect URIs" }, "has_client_secret": { @@ -9020,28 +12970,27 @@ "description": "Whether a hashed bot token is stored for this application" }, "bot_token_preview": { - "description": "The preview (last few characters) of the bot token, if any", "nullable": true, + "description": "The preview (last few characters) of the bot token, if any", "type": "string" }, "bot_token_created_at": { - "description": "ISO 8601 timestamp when the bot token was created", "nullable": true, + "description": "ISO 8601 timestamp when the bot token was created", "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "client_secret_created_at": { - "description": "ISO 8601 timestamp when the client secret was created", "nullable": true, + "description": "ISO 8601 timestamp when the client secret was created", "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "version": { - "type": "integer", - "minimum": 0, - "maximum": 2147483647, - "format": "int32", - "description": "The optimistic locking version of the application record" + "description": "The optimistic locking version of the application record", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] } }, "required": [ @@ -9064,435 +13013,114 @@ "bot_token_created_at", "client_secret_created_at", "version" - ] - }, - "LookupApplicationResponse": { - "type": "object", - "properties": { - "application": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/ApplicationAdminResponse"}]} - }, - "required": ["application"] - }, - "ApplicationUpdateResponse": { - "type": "object", - "properties": {"application": {"$ref": "#/components/schemas/ApplicationAdminResponse"}}, - "required": ["application"] - }, - "TransferApplicationOwnershipRequest": { - "type": "object", - "properties": {"new_owner_id": {"$ref": "#/components/schemas/SnowflakeType"}}, - "required": ["new_owner_id"] - }, - "ListArchivesResponseSchema": { - "type": "object", - "properties": { - "archives": {"type": "array", "items": {"$ref": "#/components/schemas/AdminArchiveResponseSchema"}} - }, - "required": ["archives"] - }, - "AdminArchiveResponseSchema": { - "type": "object", - "properties": { - "archive_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "subject_type": { - "type": "string", - "enum": ["user", "guild"], - "description": "Type of subject being archived" - }, - "subject_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "requested_by": {"$ref": "#/components/schemas/SnowflakeType"}, - "requested_at": {"type": "string"}, - "started_at": {"nullable": true, "type": "string"}, - "completed_at": {"nullable": true, "type": "string"}, - "failed_at": {"nullable": true, "type": "string"}, - "file_size": {"nullable": true, "type": "string"}, - "progress_percent": {"type": "number"}, - "progress_step": {"nullable": true, "type": "string"}, - "error_message": {"nullable": true, "type": "string"}, - "download_url_expires_at": {"nullable": true, "type": "string"}, - "expires_at": {"nullable": true, "type": "string"} - }, - "required": [ - "archive_id", - "subject_type", - "subject_id", - "requested_by", - "requested_at", - "started_at", - "completed_at", - "failed_at", - "file_size", - "progress_percent", - "progress_step", - "error_message", - "download_url_expires_at", - "expires_at" - ] - }, - "GetArchiveResponseSchema": { - "type": "object", - "properties": { - "archive": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/AdminArchiveResponseSchema"}]} - }, - "required": ["archive"] - }, - "DownloadUrlResponseSchema": { - "type": "object", - "properties": {"downloadUrl": {"type": "string"}, "expiresAt": {"type": "string"}}, - "required": ["downloadUrl", "expiresAt"] - }, - "AuditLogsListResponseSchema": { - "type": "object", - "properties": { - "logs": {"type": "array", "items": {"$ref": "#/components/schemas/AdminAuditLogResponseSchema"}}, - "total": {"type": "number"} - }, - "required": ["logs", "total"] - }, - "AdminAuditLogResponseSchema": { - "type": "object", - "properties": { - "log_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "admin_user_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "admin_user": { - "nullable": true, - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "username": {"type": "string"}, - "discriminator": {"type": "string"}, - "global_name": {"nullable": true, "type": "string"} - }, - "required": ["id", "username", "discriminator", "global_name"] - }, - "target_type": {"type": "string"}, - "target_id": { - "type": "string", - "description": "The ID of the affected entity (user, channel, role, invite code, etc.)" - }, - "target_user": { - "nullable": true, - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "username": {"type": "string"}, - "discriminator": {"type": "string"}, - "global_name": {"nullable": true, "type": "string"} - }, - "required": ["id", "username", "discriminator", "global_name"] - }, - "target_guild": { - "nullable": true, - "type": "object", - "properties": {"id": {"$ref": "#/components/schemas/SnowflakeType"}, "name": {"type": "string"}}, - "required": ["id", "name"] - }, - "target_channel": { - "nullable": true, - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"nullable": true, "type": "string"}, - "type": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4, 998, 999], - "description": "The type of the channel" - }, - "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]} - }, - "required": ["id", "name", "type", "guild_id"] - }, - "related_users": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "username": {"type": "string"}, - "discriminator": {"type": "string"}, - "global_name": {"nullable": true, "type": "string"} - }, - "required": ["id", "username", "discriminator", "global_name"] - }, - "patternProperties": { - "^(0|[1-9][0-9]*)$": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "username": {"type": "string"}, - "discriminator": {"type": "string"}, - "global_name": {"nullable": true, "type": "string"} - }, - "required": ["id", "username", "discriminator", "global_name"] - } - } - }, - "related_guilds": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {"id": {"$ref": "#/components/schemas/SnowflakeType"}, "name": {"type": "string"}}, - "required": ["id", "name"] - }, - "patternProperties": { - "^(0|[1-9][0-9]*)$": { - "type": "object", - "properties": {"id": {"$ref": "#/components/schemas/SnowflakeType"}, "name": {"type": "string"}}, - "required": ["id", "name"] - } - } - }, - "related_channels": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"nullable": true, "type": "string"}, - "type": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4, 998, 999], - "description": "The type of the channel" - }, - "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]} - }, - "required": ["id", "name", "type", "guild_id"] - }, - "patternProperties": { - "^(0|[1-9][0-9]*)$": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"nullable": true, "type": "string"}, - "type": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4, 998, 999], - "description": "The type of the channel" - }, - "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]} - }, - "required": ["id", "name", "type", "guild_id"] - } - } - }, - "action": {"type": "string"}, - "audit_log_reason": {"nullable": true, "type": "string"}, - "metadata": {"type": "object", "additionalProperties": {"type": "string"}}, - "created_at": {"type": "string"} - }, - "required": [ - "log_id", - "admin_user_id", - "admin_user", - "target_type", - "target_id", - "target_user", - "target_guild", - "target_channel", - "related_users", - "related_guilds", - "related_channels", - "action", - "audit_log_reason", - "metadata", - "created_at" - ] - }, - "AdminBlocklistTypeListResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "list_type": {"$ref": "#/components/schemas/AdminBlocklistListType"}, - "description": { - "type": "string", - "description": "What the blocklist matches and how matching is performed" - }, - "value_field": { - "type": "string", - "description": "The request body field that carries the entry value when adding to this blocklist" - }, - "fields": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 8, - "description": "Fields entries of this blocklist accept beyond the value itself" - }, - "scoped": { - "type": "boolean", - "description": "Whether entries are scoped to a profile field and a scope must be supplied" - }, - "supports_bulk_create": { - "type": "boolean", - "description": "Whether PUT on the entry collection is accepted" - }, - "supports_bulk_delete": { - "type": "boolean", - "description": "Whether DELETE on the entry collection is accepted" - }, - "supports_update": {"type": "boolean", "description": "Whether PATCH on a single entry is accepted"} - }, - "required": [ - "list_type", - "description", - "value_field", - "fields", - "scoped", - "supports_bulk_create", - "supports_bulk_delete", - "supports_update" - ] - }, - "maxItems": 50, - "description": "Every blocklist exposed by this instance" - } - }, - "required": ["items"] - }, - "AdminBlocklistListType": { - "enum": [ - "ip", - "email", - "email-domain-suspicious", - "phrase", - "url", - "url-domain", - "file-sha", - "avatar-hash", - "profile-substring" ], - "type": "string", - "description": "The blocklist an entry belongs to" + "additionalProperties": false }, - "AdminBlocklistEntryListResponse": { + "ChannelType": { + "description": "The type of the channel", + "type": "integer", + "enum": [0, 1, 2, 3, 4, 998, 999], + "format": "int32", + "x-enumNames": [ + "GUILD_TEXT", + "DM", + "GUILD_VOICE", + "GROUP_DM", + "GUILD_CATEGORY", + "GUILD_LINK", + "DM_PERSONAL_NOTES" + ], + "x-enumDescriptions": [ + "A text channel within a guild", + "A direct message between users", + "A voice channel within a guild", + "A group direct message between users", + "A category that contains channels", + "A link channel for external resources", + "Personal notes DM channel" + ] + }, + "BanProfileSubstringRequest": { "type": "object", "properties": { - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "list_type": {"$ref": "#/components/schemas/AdminBlocklistListType"}, - "value": {"type": "string", "description": "The canonical stored value of the entry"}, - "scope": { - "description": "The profile field the entry is scoped to, or null when the blocklist is unscoped", - "nullable": true, - "type": "string" - }, - "category": { - "description": "The category slug stored alongside the entry, or null", - "nullable": true, - "type": "string" - }, - "severity": { - "description": "The stored severity, or null when the blocklist has no severity", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/Int32Type"}] - }, - "source_url": { - "description": "The upstream source the entry was imported from, or null", - "nullable": true, - "type": "string" - }, - "notes": { - "description": "The internal notes stored alongside the entry, or null", - "nullable": true, - "type": "string" - }, - "content_type": { - "description": "The MIME type hint stored alongside the entry, or null", - "nullable": true, - "type": "string" - }, - "match_subdomains": { - "description": "Whether subdomains are covered by the entry, or null when the blocklist has no such flag", - "nullable": true, - "type": "boolean" - }, - "reason": { - "description": "The stored reason for the entry, or null", - "nullable": true, - "type": "string" - }, - "expires_at": { - "description": "ISO 8601 timestamp when the entry expires, or null", - "nullable": true, - "type": "string" - }, - "created_at": { - "description": "ISO 8601 timestamp when the entry was added, or null", - "nullable": true, - "type": "string" - }, - "created_by_user_id": { - "description": "The admin who added the entry, or null when unknown", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] - } - }, - "required": [ - "list_type", - "value", - "scope", - "category", - "severity", - "source_url", - "notes", - "content_type", - "match_subdomains", - "reason", - "expires_at", - "created_at", - "created_by_user_id" - ] - }, - "maxItems": 200, - "description": "The blocklist entries in this page, ordered by value" + "scope": {"type": "string", "enum": ["username", "global_name", "nickname", "bio", "pronouns"]}, + "substrings": {"minItems": 1, "maxItems": 1000, "type": "array", "items": {"type": "string"}}, + "reason": {"type": "string"}, + "notes": {"type": "string"} + }, + "required": ["scope", "substrings"] + }, + "BanAvatarHashRequest": { + "type": "object", + "properties": { + "hashes": {"minItems": 1, "maxItems": 1000, "type": "array", "items": {"type": "string"}}, + "category": {"type": "string"}, + "severity": {"type": "integer", "minimum": 0, "maximum": 3}, + "source_url": {"type": "string"}, + "reason": {"type": "string"}, + "notes": {"type": "string"} + }, + "required": ["hashes"] + }, + "BanFileShaRequest": { + "type": "object", + "properties": { + "sha256_hex": {"description": "SHA-256 in hex", "type": "string"}, + "category": {"type": "string"}, + "severity": {"type": "integer", "minimum": 0, "maximum": 3}, + "content_type": {"description": "Optional MIME type hint for observability", "type": "string"}, + "source_url": {"type": "string"}, + "notes": {"type": "string"} + }, + "required": ["sha256_hex"] + }, + "BanUrlDomainRequest": { + "type": "object", + "properties": { + "domain": {"description": "Domain to ban (e.g. example.com)", "type": "string"}, + "match_subdomains": { + "default": true, + "description": "If true, any subdomain rooted at this domain is also banned", + "type": "boolean" }, - "has_more": { - "type": "boolean", - "description": "Whether another page can be fetched with the next_after cursor" + "category": {"description": "Category / source slug (defaults to \"manual\")", "type": "string"}, + "severity": { + "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)", + "type": "integer", + "minimum": 0, + "maximum": 3 }, - "next_after": { - "description": "Cursor to send as after on the next request, or null when this is the last page", - "nullable": true, + "source_url": {"description": "Upstream source URL if imported from a feed", "type": "string"}, + "notes": {"description": "Internal notes for audit trail", "type": "string"} + }, + "required": ["domain"] + }, + "BanUrlRequest": { + "type": "object", + "properties": { + "url": {"description": "Absolute URL to ban. Canonicalized before storage.", "type": "string"}, + "category": {"description": "Category / source slug (defaults to \"manual\")", "type": "string"}, + "severity": { + "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)", + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + "source_url": {"description": "Upstream source URL if imported from a feed", "type": "string"}, + "notes": {"description": "Internal notes for audit trail", "type": "string"} + }, + "required": ["url"] + }, + "BanPhraseRequest": { + "type": "object", + "properties": { + "phrase": { + "description": "Phrase to ban. Matching is case-insensitive and also normalizes common bypass tricks such as inserted whitespace, punctuation, invisible characters, and compatibility glyphs.", "type": "string" } }, - "required": ["items", "has_more", "next_after"] + "required": ["phrase"] }, - "Int32Type": {"type": "integer", "minimum": 0, "maximum": 2147483647, "format": "int32"}, - "AdminBlocklistEntryCreateRequest": { - "oneOf": [ - {"$ref": "#/components/schemas/BanIpRequest"}, - {"$ref": "#/components/schemas/BanEmailRequest"}, - {"$ref": "#/components/schemas/SuspiciousEmailDomainRequest"}, - {"$ref": "#/components/schemas/BanPhraseRequest"}, - {"$ref": "#/components/schemas/BanUrlRequest"}, - {"$ref": "#/components/schemas/BanUrlDomainRequest"}, - {"$ref": "#/components/schemas/BanFileShaRequest"}, - {"$ref": "#/components/schemas/BanAvatarHashRequest"}, - {"$ref": "#/components/schemas/BanProfileSubstringRequest"} - ], - "description": "The entry to add, in the shape the blocklist named by list_type accepts" - }, - "BanIpRequest": { - "type": "object", - "properties": {"ip": {"type": "string", "description": "IPv4/IPv6 address or CIDR range to ban"}}, - "required": ["ip"] - }, - "BanEmailRequest": { - "type": "object", - "properties": {"email": {"$ref": "#/components/schemas/EmailType"}}, - "required": ["email"] - }, - "EmailType": {"type": "string", "format": "email"}, "SuspiciousEmailDomainRequest": { "type": "object", "properties": { @@ -9506,522 +13134,298 @@ }, "required": ["domain"] }, - "BanPhraseRequest": { + "BanEmailRequest": { "type": "object", "properties": { - "phrase": { - "type": "string", - "description": "Phrase to ban. Matching is case-insensitive and also normalizes common bypass tricks such as inserted whitespace, punctuation, invisible characters, and compatibility glyphs." - } + "email": {"description": "Email address to ban", "allOf": [{"$ref": "#/components/schemas/EmailType"}]} }, - "required": ["phrase"] + "required": ["email"] }, - "BanUrlRequest": { + "BanIpRequest": { "type": "object", - "properties": { - "url": {"type": "string", "description": "Absolute URL to ban. Canonicalized before storage."}, - "category": {"type": "string", "description": "Category / source slug (defaults to \"manual\")"}, - "severity": { - "type": "integer", - "minimum": 0, - "maximum": 3, - "format": "int32", - "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)" - }, - "source_url": {"type": "string", "description": "Upstream source URL if imported from a feed"}, - "notes": {"type": "string", "description": "Internal notes for audit trail"} - }, - "required": ["url"] - }, - "BanUrlDomainRequest": { - "type": "object", - "properties": { - "domain": {"type": "string", "description": "Domain to ban (e.g. example.com)"}, - "match_subdomains": { - "type": "boolean", - "description": "If true, any subdomain rooted at this domain is also banned" - }, - "category": {"type": "string", "description": "Category / source slug (defaults to \"manual\")"}, - "severity": { - "type": "integer", - "minimum": 0, - "maximum": 3, - "format": "int32", - "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)" - }, - "source_url": {"type": "string", "description": "Upstream source URL if imported from a feed"}, - "notes": {"type": "string", "description": "Internal notes for audit trail"} - }, - "required": ["domain"] - }, - "BanFileShaRequest": { - "type": "object", - "properties": { - "sha256_hex": {"type": "string", "description": "SHA-256 in hex"}, - "category": {"type": "string"}, - "severity": {"type": "integer", "minimum": 0, "maximum": 3, "format": "int32"}, - "content_type": {"type": "string", "description": "Optional MIME type hint for observability"}, - "source_url": {"type": "string"}, - "notes": {"type": "string"} - }, - "required": ["sha256_hex"] - }, - "BanAvatarHashRequest": { - "type": "object", - "properties": { - "hashes": {"type": "array", "items": {"type": "string"}, "minItems": 1, "maxItems": 1000}, - "category": {"type": "string"}, - "severity": {"type": "integer", "minimum": 0, "maximum": 3, "format": "int32"}, - "source_url": {"type": "string"}, - "reason": {"type": "string"}, - "notes": {"type": "string"} - }, - "required": ["hashes"] - }, - "BanProfileSubstringRequest": { - "type": "object", - "properties": { - "scope": {"enum": ["username", "global_name", "nickname", "bio", "pronouns"], "type": "string"}, - "substrings": {"type": "array", "items": {"type": "string"}, "minItems": 1, "maxItems": 1000}, - "reason": {"type": "string"}, - "notes": {"type": "string"} - }, - "required": ["scope", "substrings"] - }, - "BulkJobResponse": { - "type": "object", - "properties": {"job_id": {"$ref": "#/components/schemas/SnowflakeType"}}, - "required": ["job_id"] - }, - "BulkBanFileShasRequest": { - "type": "object", - "properties": { - "sha256_list": { - "type": "array", - "items": {"type": "string"}, - "minItems": 1, - "maxItems": 10000, - "description": "Array of SHA-256 hex strings to ban" - } - }, - "required": ["sha256_list"] - }, - "AdminBlocklistBulkDeleteRequest": { - "oneOf": [ - {"$ref": "#/components/schemas/CheckAvatarHashRequest"}, - {"$ref": "#/components/schemas/BanProfileSubstringRequest"} - ], - "description": "The entries to remove, in the shape the blocklist named by list_type accepts" + "properties": {"ip": {"description": "IPv4/IPv6 address or CIDR range to ban", "type": "string"}}, + "required": ["ip"] }, + "EmailType": {"type": "string"}, "CheckAvatarHashRequest": { "type": "object", - "properties": {"hashes": {"type": "array", "items": {"type": "string"}, "minItems": 1, "maxItems": 1000}}, + "properties": {"hashes": {"minItems": 1, "maxItems": 1000, "type": "array", "items": {"type": "string"}}}, "required": ["hashes"] }, - "BanCheckResponseSchema": { - "type": "object", - "properties": {"banned": {"type": "boolean"}}, - "required": ["banned"] - }, - "AdminBlocklistEntryUpdateRequest": { - "oneOf": [ - {"$ref": "#/components/schemas/AdminBlocklistUrlUpdateRequest"}, - {"$ref": "#/components/schemas/AdminBlocklistUrlDomainUpdateRequest"}, - {"$ref": "#/components/schemas/AdminBlocklistFileShaUpdateRequest"}, - {"$ref": "#/components/schemas/AdminBlocklistAvatarHashUpdateRequest"}, - {"$ref": "#/components/schemas/AdminBlocklistProfileSubstringUpdateRequest"} - ], - "description": "The stored fields to write, in the shape the blocklist named by list_type accepts" - }, - "AdminBlocklistUrlUpdateRequest": { + "AdminBlocklistProfileSubstringUpdateRequest": { "type": "object", "properties": { - "category": {"type": "string", "description": "Category / source slug (defaults to \"manual\")"}, - "severity": { - "type": "integer", - "minimum": 0, - "maximum": 3, - "format": "int32", - "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)" - }, - "source_url": {"type": "string", "description": "Upstream source URL if imported from a feed"}, - "notes": {"type": "string", "description": "Internal notes for audit trail"} - } + "scope": {"type": "string", "enum": ["username", "global_name", "nickname", "bio", "pronouns"]}, + "reason": {"type": "string"}, + "notes": {"type": "string"} + }, + "required": ["scope"] }, - "AdminBlocklistUrlDomainUpdateRequest": { + "AdminBlocklistAvatarHashUpdateRequest": { "type": "object", "properties": { - "match_subdomains": { - "type": "boolean", - "description": "If true, any subdomain rooted at this domain is also banned" - }, - "category": {"type": "string", "description": "Category / source slug (defaults to \"manual\")"}, - "severity": { - "type": "integer", - "minimum": 0, - "maximum": 3, - "format": "int32", - "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)" - }, - "source_url": {"type": "string", "description": "Upstream source URL if imported from a feed"}, - "notes": {"type": "string", "description": "Internal notes for audit trail"} + "category": {"type": "string"}, + "severity": {"type": "integer", "minimum": 0, "maximum": 3}, + "source_url": {"type": "string"}, + "reason": {"type": "string"}, + "notes": {"type": "string"} } }, "AdminBlocklistFileShaUpdateRequest": { "type": "object", "properties": { "category": {"type": "string"}, - "severity": {"type": "integer", "minimum": 0, "maximum": 3, "format": "int32"}, - "content_type": {"type": "string", "description": "Optional MIME type hint for observability"}, + "severity": {"type": "integer", "minimum": 0, "maximum": 3}, + "content_type": {"description": "Optional MIME type hint for observability", "type": "string"}, "source_url": {"type": "string"}, "notes": {"type": "string"} } }, - "AdminBlocklistAvatarHashUpdateRequest": { + "AdminBlocklistUrlDomainUpdateRequest": { "type": "object", "properties": { - "category": {"type": "string"}, - "severity": {"type": "integer", "minimum": 0, "maximum": 3, "format": "int32"}, - "source_url": {"type": "string"}, - "reason": {"type": "string"}, - "notes": {"type": "string"} + "match_subdomains": { + "default": true, + "description": "If true, any subdomain rooted at this domain is also banned", + "type": "boolean" + }, + "category": {"description": "Category / source slug (defaults to \"manual\")", "type": "string"}, + "severity": { + "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)", + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + "source_url": {"description": "Upstream source URL if imported from a feed", "type": "string"}, + "notes": {"description": "Internal notes for audit trail", "type": "string"} } }, - "AdminBlocklistProfileSubstringUpdateRequest": { + "AdminBlocklistUrlUpdateRequest": { "type": "object", "properties": { - "scope": {"enum": ["username", "global_name", "nickname", "bio", "pronouns"], "type": "string"}, - "reason": {"type": "string"}, - "notes": {"type": "string"} - }, - "required": ["scope"] + "category": {"description": "Category / source slug (defaults to \"manual\")", "type": "string"}, + "severity": { + "description": "Severity: 0 allow, 1 warn, 2 block, 3 block+report (default 2)", + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + "source_url": {"description": "Upstream source URL if imported from a feed", "type": "string"}, + "notes": {"description": "Internal notes for audit trail", "type": "string"} + } }, - "AdminBulkJobCreateRequest": { - "oneOf": [ - {"$ref": "#/components/schemas/UpdateUserFlagsAdminBulkJobCreateRequest"}, - {"$ref": "#/components/schemas/UpdateSuspiciousActivityFlagsAdminBulkJobCreateRequest"}, - {"$ref": "#/components/schemas/UpdateGuildFeaturesAdminBulkJobCreateRequest"}, - {"$ref": "#/components/schemas/AddGuildMembersAdminBulkJobCreateRequest"}, - {"$ref": "#/components/schemas/ScheduleUserDeletionAdminBulkJobCreateRequest"}, - {"$ref": "#/components/schemas/DeleteUserMessagesAdminBulkJobCreateRequest"} - ] + "DeletionReasonCode": { + "description": "Reason the account was scheduled for deletion", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": [ + "USER_REQUESTED", + "OTHER", + "SPAM", + "CHEATING_OR_EXPLOITATION", + "COORDINATED_RAIDING", + "AUTOMATION_OR_SELFBOT", + "NONCONSENSUAL_SEXUAL_CONTENT", + "SCAM_OR_SOCIAL_ENGINEERING", + "CHILD_SEXUAL_CONTENT", + "PRIVACY_VIOLATION_OR_DOXXING", + "HARASSMENT_OR_BULLYING", + "PAYMENT_FRAUD", + "CHILD_SAFETY_VIOLATION", + "BILLING_DISPUTE_OR_ABUSE", + "UNSOLICITED_EXPLICIT_CONTENT", + "GRAPHIC_VIOLENCE", + "BAN_EVASION", + "TOKEN_OR_CREDENTIAL_SCAM", + "INACTIVITY", + "HATE_SPEECH_OR_EXTREMIST_CONTENT", + "MALICIOUS_LINKS_OR_MALWARE", + "IMPERSONATION_OR_FAKE_IDENTITY" + ], + "enum": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22] }, - "UpdateUserFlagsAdminBulkJobCreateRequest": { - "type": "object", - "properties": { - "user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "List of user IDs to update" - }, - "add_flags": { - "type": "array", - "items": {"$ref": "#/components/schemas/UserFlags"}, - "maxItems": 64, - "description": "User flags to add to all specified users" - }, - "remove_flags": { - "type": "array", - "items": {"$ref": "#/components/schemas/UserFlags"}, - "maxItems": 64, - "description": "User flags to remove from all specified users" - }, - "task": { - "type": "string", - "enum": ["update_user_flags"], - "description": "Adds and removes account flags on every targeted user" - } - }, - "required": ["user_ids", "task"] + "GuildFeatureSchema": { + "description": "A guild feature flag Known values: ANIMATED_ICON, ANIMATED_BANNER, AUDIO_BITRATE_128_KBPS, AUDIO_BITRATE_256_KBPS, AUDIO_BITRATE_384_KBPS, BANNER, CLONE_EMOJI_DISABLED, CLONE_STICKER_DISABLED, DETACHED_BANNER, INVITE_SPLASH, INVITES_DISABLED, RAID_DETECTED, TEXT_CHANNEL_FLEXIBLE_NAMES, HIDE_OWNER_CROWN, MORE_EMOJI, MORE_STICKERS, UNLIMITED_EMOJI, UNLIMITED_STICKERS, EXPRESSION_PURGE_ALLOWED, VANITY_URL, DISCOVERABLE, PARTNERED, VERIFIED, VIP_VOICE, VOICE_E2EE, UNAVAILABLE_FOR_EVERYONE, UNAVAILABLE_FOR_EVERYONE_BUT_STAFF, UNAVAILABLE_HIDDEN, VISIONARY, LARGE_GUILD_OVERRIDE, VERY_LARGE_GUILD (other values allowed)", + "x-enumNames": [ + "ANIMATED_ICON", + "ANIMATED_BANNER", + "AUDIO_BITRATE_128_KBPS", + "AUDIO_BITRATE_256_KBPS", + "AUDIO_BITRATE_384_KBPS", + "BANNER", + "CLONE_EMOJI_DISABLED", + "CLONE_STICKER_DISABLED", + "DETACHED_BANNER", + "INVITE_SPLASH", + "INVITES_DISABLED", + "RAID_DETECTED", + "TEXT_CHANNEL_FLEXIBLE_NAMES", + "HIDE_OWNER_CROWN", + "MORE_EMOJI", + "MORE_STICKERS", + "UNLIMITED_EMOJI", + "UNLIMITED_STICKERS", + "EXPRESSION_PURGE_ALLOWED", + "VANITY_URL", + "DISCOVERABLE", + "PARTNERED", + "VERIFIED", + "VIP_VOICE", + "VOICE_E2EE", + "UNAVAILABLE_FOR_EVERYONE", + "UNAVAILABLE_FOR_EVERYONE_BUT_STAFF", + "UNAVAILABLE_HIDDEN", + "VISIONARY", + "LARGE_GUILD_OVERRIDE", + "VERY_LARGE_GUILD" + ], + "x-enumDescriptions": [ + "Guild can have an animated icon", + "Guild can have an animated banner", + "Guild can set a voice channel bitrate of up to 128 kbps", + "Guild can set a voice channel bitrate of up to 256 kbps", + "Guild can set a voice channel bitrate of up to 384 kbps", + "Guild can have a banner", + "Guild has the in-app one-click emoji clone shortcut disabled for non-members", + "Guild has the in-app one-click sticker clone shortcut disabled for non-members", + "Guild banner is detached from splash", + "Guild can have an invite splash", + "Guild has invites disabled", + "Guild has a detected raid and invites are restricted", + "Guild allows flexible text channel names", + "Guild hides the community owner crown icon", + "Legacy increased emoji slots feature", + "Legacy increased sticker slots feature", + "Guild has unlimited emoji slots", + "Guild has unlimited sticker slots", + "Guild allows purging expressions", + "Guild can have a vanity URL", + "Guild is listed in the public discovery directory", + "Guild is a partnered guild", + "Guild is verified", + "Guild has VIP voice features", + "Guild has end-to-end encryption for voice channel calls", + "Guild is unavailable for everyone", + "Guild is unavailable except for staff", + "Guild is hidden when it is force unavailable", + "Guild is a visionary guild", + "Guild has large guild overrides enabled", + "Guild has increased member capacity enabled" + ], + "type": "string" }, "UserFlags": { "type": "string", + "pattern": "^\\d+$", + "description": "User account flags (64-bit)", "format": "int64", - "pattern": "^[0-9]+$", - "description": "A single user flag value to add or remove" - }, - "UpdateSuspiciousActivityFlagsAdminBulkJobCreateRequest": { - "type": "object", - "properties": { - "user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "List of user IDs to update" + "x-bitflagValues": [ + {"name": "STAFF", "value": "1", "description": "User is a staff member"}, + {"name": "PARTNER", "value": "4", "description": "User is a partner"}, + {"name": "BUG_HUNTER", "value": "8", "description": "User is a bug hunter"}, + { + "name": "HIGH_GLOBAL_RATE_LIMIT", + "value": "8589934592", + "description": "User has elevated global rate limits" }, - "add_flags": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 32, - "description": "Suspicious activity flag names to add to all specified users" + {"name": "FRIENDLY_BOT", "value": "16", "description": "Bot accepts friend requests from users"}, + { + "name": "FRIENDLY_BOT_MANUAL_APPROVAL", + "value": "32", + "description": "Bot requires manual approval for friend requests" }, - "remove_flags": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 32, - "description": "Suspicious activity flag names to remove from all specified users" + {"name": "SPAMMER", "value": "64", "description": "User is flagged as a spammer"}, + {"name": "DELETED", "value": "17179869184", "description": "User account has been deleted"}, + { + "name": "DISABLED_SUSPICIOUS_ACTIVITY", + "value": "34359738368", + "description": "User account disabled due to suspicious activity" }, - "task": { - "type": "string", - "enum": ["update_suspicious_activity_flags"], - "description": "Adds and removes verification requirements on every targeted user" + {"name": "SELF_DELETED", "value": "68719476736", "description": "User account was self-deleted"}, + {"name": "DISABLED", "value": "274877906944", "description": "User account is disabled"}, + {"name": "HAS_SESSION_STARTED", "value": "549755813888", "description": "User has started a session"}, + {"name": "RATE_LIMIT_BYPASS", "value": "140737488355328", "description": "User can bypass rate limits"}, + {"name": "REPORT_BANNED", "value": "281474976710656", "description": "User is banned from reporting"}, + { + "name": "VERIFIED_NOT_UNDERAGE", + "value": "562949953421312", + "description": "User is verified as not underage" + }, + { + "name": "HAS_DISMISSED_PREMIUM_ONBOARDING", + "value": "2251799813685248", + "description": "User has dismissed premium onboarding" + }, + {"name": "APP_STORE_REVIEWER", "value": "9007199254740992", "description": "User is an app store reviewer"}, + { + "name": "STAFF_HIDDEN", + "value": "144115188075855872", + "description": "User staff status is hidden from public flags" + }, + { + "name": "AGE_VERIFIED_ADULT", + "value": "1152921504606846976", + "description": "User has verified their age as an adult via credit card verification" + }, + { + "name": "FORCE_INBOUND_PHONE_VERIFICATION", + "value": "2305843009213693952", + "description": "User is forced through inbound (expensive-destination) phone verification regardless of phone prefix, for debugging" + }, + { + "name": "NOT_SUSPICIOUS", + "value": "4611686018427387904", + "description": "User is permanently exempt from automatic suspicious-activity flagging on RPC session start (does not require a prior payment)" } - }, - "required": ["user_ids", "task"] - }, - "UpdateGuildFeaturesAdminBulkJobCreateRequest": { - "type": "object", - "properties": { - "guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "List of guild IDs to update" - }, - "add_features": { - "type": "array", - "items": {"$ref": "#/components/schemas/GuildFeatureSchema"}, - "maxItems": 100, - "description": "Guild features to add to all specified guilds" - }, - "remove_features": { - "type": "array", - "items": {"$ref": "#/components/schemas/GuildFeatureSchema"}, - "maxItems": 100, - "description": "Guild features to remove from all specified guilds" - }, - "task": { - "type": "string", - "enum": ["update_guild_features"], - "description": "Adds and removes features on every targeted guild" - } - }, - "required": ["guild_ids", "task"] - }, - "GuildFeatureSchema": { - "type": "string", - "description": "A guild feature flag Known values: ANIMATED_ICON, ANIMATED_BANNER, AUDIO_BITRATE_128_KBPS, AUDIO_BITRATE_256_KBPS, AUDIO_BITRATE_384_KBPS, BANNER, CLONE_EMOJI_DISABLED, CLONE_STICKER_DISABLED, DETACHED_BANNER, INVITE_SPLASH, INVITES_DISABLED, RAID_DETECTED, TEXT_CHANNEL_FLEXIBLE_NAMES, HIDE_OWNER_CROWN, MORE_EMOJI, MORE_STICKERS, UNLIMITED_EMOJI, UNLIMITED_STICKERS, EXPRESSION_PURGE_ALLOWED, VANITY_URL, DISCOVERABLE, PARTNERED, VERIFIED, VIP_VOICE, VOICE_E2EE, UNAVAILABLE_FOR_EVERYONE, UNAVAILABLE_FOR_EVERYONE_BUT_STAFF, UNAVAILABLE_HIDDEN, VISIONARY, LARGE_GUILD_OVERRIDE, VERY_LARGE_GUILD (other values allowed)" - }, - "AddGuildMembersAdminBulkJobCreateRequest": { - "type": "object", - "properties": { - "guild_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "List of user IDs to add as members" - }, - "task": { - "type": "string", - "enum": ["add_guild_members"], - "description": "Adds every targeted user to one guild" - } - }, - "required": ["guild_id", "user_ids", "task"] - }, - "ScheduleUserDeletionAdminBulkJobCreateRequest": { - "type": "object", - "properties": { - "user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "List of user IDs to schedule deletion for" - }, - "reason_code": { - "$ref": "#/components/schemas/DeletionReasonCode", - "description": "Code indicating the reason for deletion" - }, - "public_reason": {"type": "string", "description": "Public-facing reason for the deletion"}, - "days_until_deletion": { - "type": "integer", - "minimum": 1, - "maximum": 365, - "format": "int32", - "description": "Number of days until the accounts are deleted" - }, - "task": { - "type": "string", - "enum": ["schedule_user_deletion"], - "description": "Schedules account deletion for every targeted user" - } - }, - "required": ["user_ids", "reason_code", "task"] - }, - "DeletionReasonCode": { - "type": "integer", - "format": "int32", - "enum": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22], - "description": "Reason the account was scheduled for deletion" - }, - "DeleteUserMessagesAdminBulkJobCreateRequest": { - "type": "object", - "properties": { - "user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "List of user IDs whose messages will be deleted" - }, - "task": { - "type": "string", - "enum": ["delete_user_messages"], - "description": "Deletes every message authored by each targeted user, across all channels" - } - }, - "required": ["user_ids", "task"] - }, - "BrowseChannelResponse": { - "type": "object", - "properties": { - "messages": {"type": "array", "items": {"$ref": "#/components/schemas/AdminMessageSchema"}, "maxItems": 100}, - "message_responses": { - "type": "array", - "items": {"$ref": "#/components/schemas/MessageResponseSchema"}, - "maxItems": 100 - }, - "has_more": {"type": "boolean"} - }, - "required": ["messages", "has_more"] - }, - "AdminMessageSchema": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "channel_name": {"nullable": true, "type": "string"}, - "channel_nsfw": {"nullable": true, "type": "boolean"}, - "channel_content_warning_level": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] - }, - "channel_content_warning_text": {"nullable": true, "type": "string"}, - "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "guild_name": {"nullable": true, "type": "string"}, - "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, - "guild_nsfw": {"nullable": true, "type": "boolean"}, - "guild_content_warning_level": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] - }, - "guild_content_warning_text": {"nullable": true, "type": "string"}, - "author_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "author_username": {"type": "string"}, - "author_global_name": {"nullable": true, "type": "string"}, - "author_discriminator": {"type": "string"}, - "author_avatar": {"nullable": true, "type": "string"}, - "content": {"type": "string"}, - "timestamp": {"type": "string"}, - "attachments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "filename": {"type": "string"}, - "url": {"type": "string"}, - "nsfw": {"nullable": true, "type": "boolean"}, - "content_type": {"nullable": true, "type": "string"}, - "width": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, - "height": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, - "size": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}]}, - "ncmec_status": { - "type": "string", - "enum": ["not_submitted", "submitted", "failed"], - "description": "NCMEC submission status" - }, - "ncmec_report_id": {"nullable": true, "type": "string"}, - "ncmec_failure_reason": {"nullable": true, "type": "string"} - }, - "required": [ - "id", - "filename", - "url", - "nsfw", - "content_type", - "width", - "height", - "ncmec_status", - "ncmec_report_id", - "ncmec_failure_reason" - ] - }, - "maxItems": 10 - }, - "user_prior_ncmec_report_ids": {"type": "array", "items": {"type": "string"}, "maxItems": 100} - }, - "required": [ - "id", - "channel_id", - "channel_name", - "channel_nsfw", - "guild_id", - "guild_name", - "guild_nsfw_level", - "author_id", - "author_username", - "author_global_name", - "author_discriminator", - "author_avatar", - "content", - "timestamp", - "attachments" ] }, - "ContentWarningLevel": { - "type": "integer", - "format": "int32", - "enum": [0, 1], - "description": "The content warning level for a guild, category, or channel" - }, - "NSFWLevel": {"type": "integer", "format": "int32", "enum": [0, 3], "description": "The NSFW level of the guild"}, - "NonNegativeSafeIntegerType": {"type": "integer", "minimum": 0, "maximum": 9007199254740991, "format": "int53"}, "MessageResponseSchema": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier (snowflake) for this message" + "description": "The unique identifier (snowflake) for this message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "channel_id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The ID of the channel this message was sent in" + "description": "The ID of the channel this message was sent in", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "author": { + "description": "The author of the message", + "allOf": [{"$ref": "#/components/schemas/UserPartialResponse"}] }, - "author": {"$ref": "#/components/schemas/UserPartialResponse"}, "webhook_id": { "description": "The ID of the webhook that sent this message", "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "type": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4, 5, 6, 7, 19], - "description": "The type of message" + "type": {"allOf": [{"$ref": "#/components/schemas/MessageType"}]}, + "flags": { + "description": "The bitwise flags for this message", + "allOf": [{"$ref": "#/components/schemas/MessageFlags"}] }, - "flags": {"$ref": "#/components/schemas/MessageFlags"}, "content": {"type": "string", "description": "The text content of the message"}, "timestamp": { "type": "string", "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "The ISO 8601 timestamp of when the message was created" }, "edited_timestamp": { "description": "The ISO 8601 timestamp of when the message was last edited", "nullable": true, "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "pinned": {"type": "boolean", "description": "Whether the message is pinned"}, "mention_everyone": {"type": "boolean", "description": "Whether the message mentions @everyone"}, "tts": {"type": "boolean", "description": "Whether the message was sent as text-to-speech"}, "mentions": { "type": "array", - "items": {"$ref": "#/components/schemas/UserPartialResponse"}, + "items": {"allOf": [{"$ref": "#/components/schemas/UserPartialResponse"}]}, "description": "The users mentioned in the message" }, "mention_roles": { @@ -10039,7 +13443,7 @@ "description": "Users referenced from non-notifying content, embed, and snapshot text, included for client-side resolution", "nullable": true, "type": "array", - "items": {"$ref": "#/components/schemas/UserPartialResponse"} + "items": {"allOf": [{"$ref": "#/components/schemas/UserPartialResponse"}]} }, "embeds": { "description": "The embeds attached to the message", @@ -10071,23 +13475,22 @@ "type": "object", "properties": { "channel_id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The ID of the channel containing the referenced message" + "description": "The ID of the channel containing the referenced message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "message_id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The ID of the referenced message" + "description": "The ID of the referenced message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "guild_id": { "description": "The ID of the guild containing the referenced message", "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "type": {"$ref": "#/components/schemas/MessageReferenceType"} + "type": {"allOf": [{"$ref": "#/components/schemas/MessageReferenceType"}]} }, - "required": ["channel_id", "message_id", "type"] + "required": ["channel_id", "message_id", "type"], + "additionalProperties": false }, "message_snapshots": { "description": "Snapshots of forwarded messages", @@ -10114,10 +13517,12 @@ "description": "The ISO 8601 timestamp of when the call ended", "nullable": true, "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" } }, - "required": ["participants"] + "required": ["participants"], + "additionalProperties": false }, "referenced_message": { "description": "The reply target. Present and populated when the target resolved, present and null when the target is gone, absent when this message carries no default reference. Clients must tell null apart from absent by key presence.", @@ -10125,46 +13530,47 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier (snowflake) for this message" + "description": "The unique identifier (snowflake) for this message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "channel_id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The ID of the channel this message was sent in" + "description": "The ID of the channel this message was sent in", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "author": { + "description": "The author of the message", + "allOf": [{"$ref": "#/components/schemas/UserPartialResponse"}] }, - "author": {"$ref": "#/components/schemas/UserPartialResponse"}, "webhook_id": { "description": "The ID of the webhook that sent this message", "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "type": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4, 5, 6, 7, 19], - "description": "The type of message" + "type": {"allOf": [{"$ref": "#/components/schemas/MessageType"}]}, + "flags": { + "description": "The bitwise flags for this message", + "allOf": [{"$ref": "#/components/schemas/MessageFlags"}] }, - "flags": {"$ref": "#/components/schemas/MessageFlags"}, "content": {"type": "string", "description": "The text content of the message"}, "timestamp": { "type": "string", "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "The ISO 8601 timestamp of when the message was created" }, "edited_timestamp": { "description": "The ISO 8601 timestamp of when the message was last edited", "nullable": true, "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "pinned": {"type": "boolean", "description": "Whether the message is pinned"}, "mention_everyone": {"type": "boolean", "description": "Whether the message mentions @everyone"}, "tts": {"type": "boolean", "description": "Whether the message was sent as text-to-speech"}, "mentions": { "type": "array", - "items": {"$ref": "#/components/schemas/UserPartialResponse"}, + "items": {"allOf": [{"$ref": "#/components/schemas/UserPartialResponse"}]}, "description": "The users mentioned in the message" }, "mention_roles": { @@ -10182,7 +13588,7 @@ "description": "Users referenced from non-notifying content, embed, and snapshot text, included for client-side resolution", "nullable": true, "type": "array", - "items": {"$ref": "#/components/schemas/UserPartialResponse"} + "items": {"allOf": [{"$ref": "#/components/schemas/UserPartialResponse"}]} }, "embeds": { "description": "The embeds attached to the message", @@ -10214,23 +13620,22 @@ "type": "object", "properties": { "channel_id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The ID of the channel containing the referenced message" + "description": "The ID of the channel containing the referenced message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "message_id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The ID of the referenced message" + "description": "The ID of the referenced message", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "guild_id": { "description": "The ID of the guild containing the referenced message", "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "type": {"$ref": "#/components/schemas/MessageReferenceType"} + "type": {"allOf": [{"$ref": "#/components/schemas/MessageReferenceType"}]} }, - "required": ["channel_id", "message_id", "type"] + "required": ["channel_id", "message_id", "type"], + "additionalProperties": false }, "message_snapshots": { "description": "Snapshots of forwarded messages", @@ -10257,10 +13662,12 @@ "description": "The ISO 8601 timestamp of when the call ended", "nullable": true, "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" } }, - "required": ["participants"] + "required": ["participants"], + "additionalProperties": false } }, "required": [ @@ -10276,7 +13683,8 @@ "tts", "mentions", "mention_roles" - ] + ], + "additionalProperties": false } }, "required": [ @@ -10292,69 +13700,290 @@ "tts", "mentions", "mention_roles" + ], + "additionalProperties": false + }, + "AdminMessageSchema": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "channel_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "channel_name": {"nullable": true, "type": "string"}, + "channel_nsfw": {"nullable": true, "type": "boolean"}, + "channel_content_warning_level": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] + }, + "channel_content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, + "guild_name": {"nullable": true, "type": "string"}, + "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "guild_nsfw": {"nullable": true, "type": "boolean"}, + "guild_content_warning_level": { + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] + }, + "guild_content_warning_text": {"nullable": true, "type": "string", "maxLength": 200}, + "author_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "author_username": {"type": "string", "minLength": 1, "maxLength": 100}, + "author_global_name": {"nullable": true, "type": "string"}, + "author_discriminator": {"type": "string", "minLength": 1, "maxLength": 10}, + "author_avatar": {"nullable": true, "type": "string"}, + "content": {"type": "string", "maxLength": 4000}, + "timestamp": {"type": "string"}, + "attachments": { + "maxItems": 10, + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "filename": {"type": "string", "minLength": 1, "maxLength": 256}, + "url": {"type": "string", "minLength": 1, "maxLength": 2048}, + "nsfw": {"nullable": true, "type": "boolean"}, + "content_type": {"nullable": true, "type": "string"}, + "width": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, + "height": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, + "size": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}]}, + "ncmec_status": { + "description": "NCMEC submission status", + "x-enumNames": ["not_submitted", "submitting", "submitted", "failed"], + "x-enumDescriptions": [ + "Report has not been submitted to NCMEC", + "Report submission to NCMEC is in progress", + "Report has been submitted to NCMEC", + "Report submission to NCMEC failed" + ], + "enum": ["not_submitted", "submitting", "submitted", "failed"], + "type": "string" + }, + "ncmec_report_id": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 256}, + "ncmec_failure_reason": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 4000} + }, + "required": [ + "id", + "filename", + "url", + "nsfw", + "content_type", + "width", + "height", + "ncmec_status", + "ncmec_report_id", + "ncmec_failure_reason" + ], + "additionalProperties": false + } + }, + "user_prior_ncmec_report_ids": { + "maxItems": 100, + "type": "array", + "items": {"type": "string", "minLength": 1, "maxLength": 256} + } + }, + "required": [ + "id", + "channel_id", + "channel_name", + "channel_nsfw", + "guild_id", + "guild_name", + "guild_nsfw_level", + "author_id", + "author_username", + "author_global_name", + "author_discriminator", + "author_avatar", + "content", + "timestamp", + "attachments" + ], + "additionalProperties": false + }, + "NonNegativeSafeIntegerType": {"type": "integer", "minimum": 0, "maximum": 9007199254740991}, + "ContentWarningLevel": { + "description": "The content warning level for a guild, category, or channel", + "type": "integer", + "enum": [0, 1], + "format": "int32", + "x-enumNames": ["INHERIT", "CONTENT_WARNING"], + "x-enumDescriptions": [ + "No level set on this scope; channels and categories inherit from parent", + "Show a content warning before entering" ] }, - "UserPartialResponse": { + "NSFWLevel": { + "description": "The NSFW level of the guild", + "type": "integer", + "enum": [0, 3], + "format": "int32", + "x-enumNames": ["SAFE", "AGE_RESTRICTED"], + "x-enumDescriptions": ["Guild is safe for all ages", "Guild is age-restricted"] + }, + "MessageSnapshotResponse": { + "type": "object", + "properties": { + "content": {"description": "The text content of the snapshot", "nullable": true, "type": "string"}, + "timestamp": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "description": "The ISO 8601 timestamp of when the original message was created" + }, + "edited_timestamp": { + "description": "The ISO 8601 timestamp of when the original message was last edited", + "nullable": true, + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" + }, + "mentions": { + "description": "The user IDs mentioned in the snapshot", + "nullable": true, + "type": "array", + "items": {"type": "string"} + }, + "mention_roles": { + "description": "The role IDs mentioned in the snapshot", + "nullable": true, + "type": "array", + "items": {"type": "string"} + }, + "mention_channels": { + "description": "Channels mentioned in the snapshot that are visible to @everyone", + "nullable": true, + "type": "array", + "items": {"$ref": "#/components/schemas/MessageChannelMentionResponse"} + }, + "embeds": { + "description": "The embeds included in the snapshot", + "nullable": true, + "type": "array", + "items": {"$ref": "#/components/schemas/MessageEmbedResponse"} + }, + "attachments": { + "description": "The attachments included in the snapshot", + "nullable": true, + "type": "array", + "items": {"$ref": "#/components/schemas/MessageAttachmentResponse"} + }, + "stickers": { + "description": "The stickers included in the snapshot", + "nullable": true, + "type": "array", + "items": {"$ref": "#/components/schemas/MessageStickerResponse"} + }, + "type": {"allOf": [{"$ref": "#/components/schemas/MessageType"}]}, + "flags": {"allOf": [{"$ref": "#/components/schemas/MessageFlags"}]} + }, + "required": ["timestamp", "type", "flags"], + "additionalProperties": false + }, + "MessageReferenceType": { + "description": "The type of message reference", + "type": "integer", + "enum": [0, 1], + "format": "int32", + "x-enumNames": ["DEFAULT", "FORWARD"], + "x-enumDescriptions": ["Default reference (reply)", "Forwarded message reference"] + }, + "MessageReactionResponse": { + "type": "object", + "properties": { + "emoji": { + "type": "object", + "properties": { + "id": { + "description": "The ID of the custom emoji (null for Unicode emojis)", + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "name": { + "type": "string", + "description": "The name of the emoji (or Unicode character for standard emojis)" + }, + "animated": {"description": "Whether the emoji is animated", "nullable": true, "type": "boolean"} + }, + "required": ["name"], + "additionalProperties": false, + "description": "The emoji used for the reaction" + }, + "count": { + "description": "The total number of times this reaction has been used", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "me": { + "description": "Whether the current user has reacted with this emoji", + "nullable": true, + "type": "boolean" + } + }, + "required": ["emoji", "count"], + "additionalProperties": false + }, + "MessageStickerResponse": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier (snowflake) for this user" + "description": "The unique identifier of the sticker", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "username": {"type": "string", "description": "The username of the user, not unique across the platform"}, - "discriminator": {"type": "string", "description": "The four-digit discriminator tag of the user"}, - "global_name": {"description": "The display name of the user, if set", "nullable": true, "type": "string"}, - "avatar": {"description": "The hash of the user avatar image", "nullable": true, "type": "string"}, - "avatar_color": { - "description": "The dominant avatar color of the user as an integer", + "name": {"type": "string", "description": "The name of the sticker"}, + "animated": {"type": "boolean", "description": "Whether the sticker is animated"} + }, + "required": ["id", "name", "animated"], + "additionalProperties": false + }, + "MessageAttachmentResponse": { + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for this attachment", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "filename": {"type": "string", "description": "The name of the attached file"}, + "title": {"description": "The title of the attachment", "nullable": true, "type": "string"}, + "description": {"description": "The description of the attachment", "nullable": true, "type": "string"}, + "content_type": {"description": "The MIME type of the attachment", "nullable": true, "type": "string"}, + "content_hash": {"description": "The hash of the attachment content", "nullable": true, "type": "string"}, + "size": { + "description": "The size of the attachment in bytes", + "allOf": [{"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}] + }, + "url": {"description": "The URL of the attachment", "nullable": true, "type": "string"}, + "proxy_url": {"description": "The proxied URL of the attachment", "nullable": true, "type": "string"}, + "width": { + "description": "The width of the attachment in pixels (for images/videos)", "nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}] }, - "bot": {"type": "boolean", "description": "Whether the user is a bot account"}, - "system": {"type": "boolean", "description": "Whether the user is an official system user"}, - "flags": {"$ref": "#/components/schemas/PublicUserFlags"}, - "mention_flags": { - "$ref": "#/components/schemas/MentionReplyPreferences", - "description": "The user's account-wide reply mention preference" - } + "height": { + "description": "The height of the attachment in pixels (for images/videos)", + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "placeholder": { + "description": "The base64 encoded placeholder image for lazy loading", + "nullable": true, + "type": "string" + }, + "flags": {"allOf": [{"$ref": "#/components/schemas/MessageAttachmentFlags"}]}, + "nsfw": {"description": "Whether the attachment is flagged as NSFW", "nullable": true, "type": "boolean"}, + "duration": { + "description": "The duration of the media in seconds", + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "waveform": {"description": "The base64 encoded audio waveform data", "nullable": true, "type": "string"}, + "expires_at": { + "description": "The ISO 8601 timestamp when the attachment URL expires", + "nullable": true, + "type": "string" + }, + "expired": {"description": "Whether the attachment URL has expired", "nullable": true, "type": "boolean"} }, - "required": ["id", "username", "discriminator", "global_name", "avatar", "avatar_color", "flags"] - }, - "PublicUserFlags": { - "type": "integer", - "format": "int32", - "minimum": 0, - "maximum": 2147483647, - "description": "The public flags on the user account" - }, - "MentionReplyPreferences": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2], - "description": "Reply mention preference" - }, - "MessageFlags": { - "type": "integer", - "format": "int32", - "minimum": 0, - "maximum": 2147483647, - "description": "Message flags bitfield" - }, - "MessageChannelMentionResponse": { - "type": "object", - "properties": { - "id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "The ID of the mentioned channel"}, - "name": {"type": "string", "description": "The name of the mentioned channel"}, - "type": { - "type": "integer", - "minimum": 0, - "maximum": 2147483647, - "format": "int32", - "description": "The type of the mentioned channel" - } - }, - "required": ["id", "name", "type"] + "required": ["id", "filename", "size", "flags"], + "additionalProperties": false }, "MessageEmbedResponse": { "type": "object", @@ -10374,7 +14003,8 @@ "description": "The ISO 8601 timestamp of the embed content", "nullable": true, "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "description": {"description": "The description of the embed", "nullable": true, "type": "string"}, "author": { @@ -10437,104 +14067,135 @@ "children": { "description": "Internal nested embeds generated by unfurlers", "nullable": true, + "maxItems": 1, "type": "array", - "items": {"$ref": "#/components/schemas/MessageEmbedChildResponse"}, - "maxItems": 1 + "items": {"$ref": "#/components/schemas/MessageEmbedChildResponse"} } }, - "required": ["type"] + "required": ["type"], + "additionalProperties": false }, - "EmbedAuthorResponse": { + "UserPartialResponse": { "type": "object", "properties": { - "name": {"type": "string", "description": "The name of the author"}, - "url": {"description": "The URL of the author", "nullable": true, "type": "string", "format": "uri"}, - "icon_url": { - "description": "The URL of the author icon", - "nullable": true, - "type": "string", - "format": "uri" + "id": { + "description": "The unique identifier (snowflake) for this user", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "proxy_icon_url": { - "description": "The proxied URL of the author icon", + "username": {"type": "string", "description": "The username of the user, not unique across the platform"}, + "discriminator": {"type": "string", "description": "The four-digit discriminator tag of the user"}, + "global_name": {"nullable": true, "description": "The display name of the user, if set", "type": "string"}, + "avatar": {"nullable": true, "description": "The hash of the user avatar image", "type": "string"}, + "avatar_color": { "nullable": true, - "type": "string", - "format": "uri" + "description": "The dominant avatar color of the user as an integer", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "bot": {"description": "Whether the user is a bot account", "type": "boolean"}, + "system": {"description": "Whether the user is an official system user", "type": "boolean"}, + "flags": {"allOf": [{"$ref": "#/components/schemas/PublicUserFlags"}]}, + "mention_flags": { + "description": "The user's account-wide reply mention preference. Omitted when the user has no preference set (treated as NO_PREFERENCE).", + "allOf": [{"$ref": "#/components/schemas/MentionReplyPreferences"}] } }, - "required": ["name"] + "required": ["id", "username", "discriminator", "global_name", "avatar", "avatar_color", "flags"], + "additionalProperties": false }, - "EmbedMediaResponse": { + "MessageChannelMentionResponse": { "type": "object", "properties": { - "url": {"type": "string", "description": "The URL of the media"}, - "proxy_url": { - "description": "The proxied URL of the media", - "nullable": true, - "type": "string", - "format": "uri" + "id": { + "description": "The ID of the mentioned channel", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "content_type": {"description": "The MIME type of the media", "nullable": true, "type": "string"}, - "content_hash": {"description": "The hash of the media content", "nullable": true, "type": "string"}, - "width": { - "description": "The width of the media in pixels", - "nullable": true, + "name": {"type": "string", "description": "The name of the mentioned channel"}, + "type": { + "description": "The type of the mentioned channel", "allOf": [{"$ref": "#/components/schemas/Int32Type"}] - }, - "height": { - "description": "The height of the media in pixels", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/Int32Type"}] - }, - "description": {"description": "The description of the media", "nullable": true, "type": "string"}, - "placeholder": { - "description": "The base64 encoded placeholder image for lazy loading", - "nullable": true, - "type": "string" - }, - "duration": { - "description": "The duration of the media in seconds", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/Int32Type"}] - }, - "flags": {"$ref": "#/components/schemas/EmbedMediaFlags"} + } }, - "required": ["url", "flags"] + "required": ["id", "name", "type"], + "additionalProperties": false }, - "EmbedMediaFlags": { + "MessageFlags": { "type": "integer", - "format": "int32", "minimum": 0, "maximum": 2147483647, - "description": "The bitwise flags for this media" - }, - "EmbedFooterResponse": { - "type": "object", - "properties": { - "text": {"type": "string", "description": "The footer text"}, - "icon_url": { - "description": "The URL of the footer icon", - "nullable": true, - "type": "string", - "format": "uri" + "description": "The bitwise flags of the original message", + "format": "int32", + "x-bitflagValues": [ + { + "name": "SUPPRESS_EMBEDS", + "value": "4", + "description": "Do not include embeds when serialising this message" }, - "proxy_icon_url": { - "description": "The proxied URL of the footer icon", - "nullable": true, - "type": "string", - "format": "uri" - } - }, - "required": ["text"] + { + "name": "SUPPRESS_NOTIFICATIONS", + "value": "4096", + "description": "This message will not trigger push or desktop notifications" + }, + {"name": "VOICE_MESSAGE", "value": "8192", "description": "This message is a voice message"} + ] }, - "EmbedFieldResponse": { - "type": "object", - "properties": { - "name": {"type": "string", "description": "The name of the field"}, - "value": {"type": "string", "description": "The value of the field"}, - "inline": {"type": "boolean", "description": "Whether the field should be displayed inline"} - }, - "required": ["name", "value", "inline"] + "MessageType": { + "description": "The type of message", + "type": "integer", + "enum": [0, 1, 2, 3, 4, 5, 6, 7, 19], + "format": "int32", + "x-enumNames": [ + "DEFAULT", + "RECIPIENT_ADD", + "RECIPIENT_REMOVE", + "CALL", + "CHANNEL_NAME_CHANGE", + "CHANNEL_ICON_CHANGE", + "CHANNEL_PINNED_MESSAGE", + "USER_JOIN", + "REPLY" + ], + "x-enumDescriptions": [ + "A regular message", + "A system message indicating a user was added to the conversation", + "A system message indicating a user was removed from the conversation", + "A message representing a call", + "A system message indicating the channel name changed", + "A system message indicating the channel icon changed", + "A system message indicating a message was pinned", + "A system message indicating a user joined", + "A reply message" + ] + }, + "MentionReplyPreferences": { + "description": "Reply mention preference", + "type": "integer", + "enum": [0, 1, 2], + "format": "int32", + "x-enumNames": ["NO_PREFERENCE", "PREFER_MENTION", "PREFER_NO_MENTION"], + "x-enumDescriptions": [ + "Respect the sender intent on each reply, with no warning when toggling the @ mention. On a guild member, inherits the value from the user-level preference.", + "Default replies to @mention this user, and warn the sender when they disable the mention", + "Default replies to omit the @mention for this user, and warn the sender when they enable it" + ] + }, + "PublicUserFlags": { + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "description": "The public flags on the user account", + "format": "int32", + "x-bitflagValues": [ + {"name": "STAFF", "value": "1", "description": "User is a staff member"}, + {"name": "PARTNER", "value": "4", "description": "User is a partner"}, + {"name": "BUG_HUNTER", "value": "8", "description": "User is a bug hunter"}, + {"name": "FRIENDLY_BOT", "value": "16", "description": "Bot accepts friend requests from users"}, + { + "name": "FRIENDLY_BOT_MANUAL_APPROVAL", + "value": "32", + "description": "Bot requires manual approval for friend requests" + }, + {"name": "SPAMMER", "value": "64", "description": "User is flagged as a spammer"} + ] }, "MessageEmbedChildResponse": { "type": "object", @@ -10554,7 +14215,8 @@ "description": "The ISO 8601 timestamp of the embed content", "nullable": true, "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "description": {"description": "The description of the embed", "nullable": true, "type": "string"}, "author": { @@ -10615,222 +14277,148 @@ }, "nsfw": {"description": "Whether the embed is flagged as NSFW", "nullable": true, "type": "boolean"} }, - "required": ["type"] + "required": ["type"], + "additionalProperties": false }, - "MessageAttachmentResponse": { + "EmbedMediaResponse": { "type": "object", "properties": { - "id": { + "url": {"type": "string", "description": "The URL of the media"}, + "proxy_url": { + "description": "The proxied URL of the media", + "nullable": true, "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier for this attachment" + "format": "uri" }, - "filename": {"type": "string", "description": "The name of the attached file"}, - "title": {"description": "The title of the attachment", "nullable": true, "type": "string"}, - "description": {"description": "The description of the attachment", "nullable": true, "type": "string"}, - "content_type": {"description": "The MIME type of the attachment", "nullable": true, "type": "string"}, - "content_hash": {"description": "The hash of the attachment content", "nullable": true, "type": "string"}, - "size": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991, - "format": "int53", - "description": "The size of the attachment in bytes" - }, - "url": {"description": "The URL of the attachment", "nullable": true, "type": "string"}, - "proxy_url": {"description": "The proxied URL of the attachment", "nullable": true, "type": "string"}, + "content_type": {"description": "The MIME type of the media", "nullable": true, "type": "string"}, + "content_hash": {"description": "The hash of the media content", "nullable": true, "type": "string"}, "width": { - "description": "The width of the attachment in pixels (for images/videos)", + "description": "The width of the media in pixels", "nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}] }, "height": { - "description": "The height of the attachment in pixels (for images/videos)", + "description": "The height of the media in pixels", "nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}] }, + "description": {"description": "The description of the media", "nullable": true, "type": "string"}, "placeholder": { "description": "The base64 encoded placeholder image for lazy loading", "nullable": true, "type": "string" }, - "flags": {"$ref": "#/components/schemas/MessageAttachmentFlags"}, - "nsfw": {"description": "Whether the attachment is flagged as NSFW", "nullable": true, "type": "boolean"}, "duration": { "description": "The duration of the media in seconds", "nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}] }, - "waveform": {"description": "The base64 encoded audio waveform data", "nullable": true, "type": "string"}, - "expires_at": { - "description": "The ISO 8601 timestamp when the attachment URL expires", - "nullable": true, - "type": "string" - }, - "expired": {"description": "Whether the attachment URL has expired", "nullable": true, "type": "boolean"} + "flags": {"allOf": [{"$ref": "#/components/schemas/EmbedMediaFlags"}]} }, - "required": ["id", "filename", "size", "flags"] + "required": ["url", "flags"], + "additionalProperties": false + }, + "EmbedAuthorResponse": { + "type": "object", + "properties": { + "name": {"type": "string", "description": "The name of the author"}, + "url": {"description": "The URL of the author", "nullable": true, "type": "string", "format": "uri"}, + "icon_url": { + "description": "The URL of the author icon", + "nullable": true, + "type": "string", + "format": "uri" + }, + "proxy_icon_url": { + "description": "The proxied URL of the author icon", + "nullable": true, + "type": "string", + "format": "uri" + } + }, + "required": ["name"], + "additionalProperties": false + }, + "EmbedFieldResponse": { + "type": "object", + "properties": { + "name": {"type": "string", "description": "The name of the field"}, + "value": {"type": "string", "description": "The value of the field"}, + "inline": {"type": "boolean", "description": "Whether the field should be displayed inline"} + }, + "required": ["name", "value", "inline"], + "additionalProperties": false + }, + "EmbedFooterResponse": { + "type": "object", + "properties": { + "text": {"type": "string", "description": "The footer text"}, + "icon_url": { + "description": "The URL of the footer icon", + "nullable": true, + "type": "string", + "format": "uri" + }, + "proxy_icon_url": { + "description": "The proxied URL of the footer icon", + "nullable": true, + "type": "string", + "format": "uri" + } + }, + "required": ["text"], + "additionalProperties": false + }, + "EmbedMediaFlags": { + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "description": "The bitwise flags for this media", + "format": "int32", + "x-bitflagValues": [ + {"name": "CONTAINS_EXPLICIT_MEDIA", "value": "16", "description": "Embed media contains explicit content"}, + {"name": "IS_ANIMATED", "value": "32", "description": "Embed media is animated"} + ] }, "MessageAttachmentFlags": { "type": "integer", - "format": "int32", "minimum": 0, "maximum": 2147483647, - "description": "Attachment flags" - }, - "MessageStickerResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier of the sticker" - }, - "name": {"type": "string", "description": "The name of the sticker"}, - "animated": {"type": "boolean", "description": "Whether the sticker is animated"} - }, - "required": ["id", "name", "animated"] - }, - "MessageReactionResponse": { - "type": "object", - "properties": { - "emoji": { - "type": "object", - "properties": { - "id": { - "description": "The ID of the custom emoji (null for Unicode emojis)", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] - }, - "name": { - "type": "string", - "description": "The name of the emoji (or Unicode character for standard emojis)" - }, - "animated": {"description": "Whether the emoji is animated", "nullable": true, "type": "boolean"} - }, - "required": ["name"], - "description": "The emoji used for the reaction" - }, - "count": { - "type": "integer", - "minimum": 0, - "maximum": 2147483647, - "format": "int32", - "description": "The total number of times this reaction has been used" - }, - "me": { - "description": "Whether the current user has reacted with this emoji", - "nullable": true, - "type": "boolean" - } - }, - "required": ["emoji", "count"] - }, - "MessageReferenceType": { - "type": "integer", + "description": "The bitwise flags for this attachment", "format": "int32", - "enum": [0, 1], - "description": "The type of message reference" - }, - "MessageSnapshotResponse": { - "type": "object", - "properties": { - "content": {"description": "The text content of the snapshot", "nullable": true, "type": "string"}, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "The ISO 8601 timestamp of when the original message was created" + "x-bitflagValues": [ + {"name": "IS_SPOILER", "value": "8", "description": "Attachment is marked as a spoiler"}, + { + "name": "CONTAINS_EXPLICIT_MEDIA", + "value": "16", + "description": "Attachment contains explicit media content" }, - "edited_timestamp": { - "description": "The ISO 8601 timestamp of when the original message was last edited", - "nullable": true, - "type": "string", - "format": "date-time" - }, - "mentions": { - "description": "The user IDs mentioned in the snapshot", - "nullable": true, - "type": "array", - "items": {"type": "string"} - }, - "mention_roles": { - "description": "The role IDs mentioned in the snapshot", - "nullable": true, - "type": "array", - "items": {"type": "string"} - }, - "mention_channels": { - "description": "Channels mentioned in the snapshot that are visible to @everyone", - "nullable": true, - "type": "array", - "items": {"$ref": "#/components/schemas/MessageChannelMentionResponse"} - }, - "embeds": { - "description": "The embeds included in the snapshot", - "nullable": true, - "type": "array", - "items": {"$ref": "#/components/schemas/MessageEmbedResponse"} - }, - "attachments": { - "description": "The attachments included in the snapshot", - "nullable": true, - "type": "array", - "items": {"$ref": "#/components/schemas/MessageAttachmentResponse"} - }, - "stickers": { - "description": "The stickers included in the snapshot", - "nullable": true, - "type": "array", - "items": {"$ref": "#/components/schemas/MessageStickerResponse"} - }, - "type": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4, 5, 6, 7, 19], - "description": "The type of message" - }, - "flags": {"$ref": "#/components/schemas/MessageFlags"} - }, - "required": ["timestamp", "type", "flags"] - }, - "LookupMessageResponse": { - "type": "object", - "properties": { - "messages": {"type": "array", "items": {"$ref": "#/components/schemas/AdminMessageSchema"}, "maxItems": 100}, - "message_responses": { - "type": "array", - "items": {"$ref": "#/components/schemas/MessageResponseSchema"}, - "maxItems": 100 - }, - "message_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]} - }, - "required": ["messages", "message_id"] - }, - "DeleteMessageResponse": { - "type": "object", - "properties": {"success": {"type": "boolean", "enum": [true]}}, - "required": ["success"] + {"name": "IS_ANIMATED", "value": "32", "description": "Attachment is animated"} + ] }, "DiscoveryAdminPendingApplicationResponse": { "type": "object", "properties": { - "guild_id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "Guild ID"}, + "guild_id": {"description": "Guild ID", "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, "guild_name": {"type": "string", "description": "Guild name"}, - "guild_icon": {"description": "Guild icon hash", "nullable": true, "type": "string"}, - "guild_owner_id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "Guild owner user ID"}, - "guild_owner_username": {"description": "Guild owner username", "nullable": true, "type": "string"}, - "guild_owner_global_name": {"description": "Guild owner display name", "nullable": true, "type": "string"}, - "guild_owner_discriminator": {"description": "Guild owner discriminator", "nullable": true, "type": "string"}, + "guild_icon": {"nullable": true, "description": "Guild icon hash", "type": "string"}, + "guild_owner_id": { + "description": "Guild owner user ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "guild_owner_username": {"nullable": true, "description": "Guild owner username", "type": "string"}, + "guild_owner_global_name": {"nullable": true, "description": "Guild owner display name", "type": "string"}, + "guild_owner_discriminator": {"nullable": true, "description": "Guild owner discriminator", "type": "string"}, "guild_member_count": {"type": "number", "description": "Approximate member count"}, "guild_nsfw_level": { - "description": "NSFW level of the guild", "nullable": true, + "description": "NSFW level of the guild", "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}] }, "guild_features": {"type": "array", "items": {"type": "string"}, "description": "Guild feature flags"}, "description": {"type": "string", "description": "Discovery description"}, "category_type": {"type": "number", "description": "Discovery category type"}, - "primary_language": {"description": "Primary community language", "nullable": true, "type": "string"}, + "primary_language": {"nullable": true, "description": "Primary community language", "type": "string"}, "custom_tags": {"type": "array", "items": {"type": "string"}, "description": "Custom discovery tags"}, "applied_at": {"type": "string", "description": "Application timestamp"} }, @@ -10850,87 +14438,51 @@ "primary_language", "custom_tags", "applied_at" - ] + ], + "additionalProperties": false }, - "DiscoveryApplicationResponse": { - "type": "object", - "properties": { - "guild_id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "Guild ID"}, - "guild_nsfw_level": { - "description": "NSFW level of the guild", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}] - }, - "status": {"type": "string", "description": "Application status"}, - "description": {"type": "string", "description": "Discovery description"}, - "category_type": {"type": "number", "description": "Discovery category type"}, - "primary_language": {"description": "Primary community language", "nullable": true, "type": "string"}, - "custom_tags": {"type": "array", "items": {"type": "string"}, "description": "Custom discovery tags"}, - "applied_at": {"type": "string", "description": "Application timestamp"}, - "reviewed_at": {"description": "Review timestamp", "nullable": true, "type": "string"}, - "review_reason": {"description": "Review reason (approval/rejection)", "nullable": true, "type": "string"}, - "removed_at": {"description": "Removal timestamp", "nullable": true, "type": "string"}, - "removal_reason": {"description": "Removal reason", "nullable": true, "type": "string"} - }, - "required": ["guild_id", "status", "description", "category_type", "custom_tags", "applied_at"] - }, - "DiscoveryAdminApplicationUpdateRequest": { - "oneOf": [ - {"$ref": "#/components/schemas/ApprovedDiscoveryAdminApplicationUpdateRequest"}, - {"$ref": "#/components/schemas/RejectedDiscoveryAdminApplicationUpdateRequest"} - ] - }, - "ApprovedDiscoveryAdminApplicationUpdateRequest": { - "type": "object", - "properties": { - "reason": {"type": "string", "maxLength": 500, "description": "Review reason"}, - "status": {"type": "string", "enum": ["approved"], "description": "Approve the pending application"} - }, - "required": ["status"] - }, - "RejectedDiscoveryAdminApplicationUpdateRequest": { - "type": "object", - "properties": { - "reason": {"type": "string", "minLength": 1, "maxLength": 500, "description": "Rejection reason"}, - "status": {"type": "string", "enum": ["rejected"], "description": "Reject the pending application"} - }, - "required": ["reason", "status"] - }, - "DiscoveryCategoryListResponse": { - "type": "array", - "items": {"$ref": "#/components/schemas/DiscoveryCategoryResponse"} + "DiscoveryRejectionReason": { + "type": "string", + "minLength": 1, + "maxLength": 500, + "description": "Rejection reason" }, + "DiscoveryReviewReason": {"type": "string", "maxLength": 500, "description": "Review reason"}, "DiscoveryCategoryResponse": { "type": "object", "properties": { "id": {"type": "number", "description": "Category ID"}, "name": {"type": "string", "description": "Category display name"} }, - "required": ["id", "name"] + "required": ["id", "name"], + "additionalProperties": false }, "DiscoveryAdminListedGuildResponse": { "type": "object", "properties": { - "guild_id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "Guild ID"}, + "guild_id": {"description": "Guild ID", "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, "guild_name": {"type": "string", "description": "Guild name"}, - "guild_icon": {"description": "Guild icon hash", "nullable": true, "type": "string"}, - "guild_owner_id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "Guild owner user ID"}, - "guild_owner_username": {"description": "Guild owner username", "nullable": true, "type": "string"}, - "guild_owner_global_name": {"description": "Guild owner display name", "nullable": true, "type": "string"}, - "guild_owner_discriminator": {"description": "Guild owner discriminator", "nullable": true, "type": "string"}, + "guild_icon": {"nullable": true, "description": "Guild icon hash", "type": "string"}, + "guild_owner_id": { + "description": "Guild owner user ID", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "guild_owner_username": {"nullable": true, "description": "Guild owner username", "type": "string"}, + "guild_owner_global_name": {"nullable": true, "description": "Guild owner display name", "type": "string"}, + "guild_owner_discriminator": {"nullable": true, "description": "Guild owner discriminator", "type": "string"}, "guild_member_count": {"type": "number", "description": "Approximate member count"}, "guild_nsfw_level": { - "description": "NSFW level of the guild", "nullable": true, + "description": "NSFW level of the guild", "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}] }, "guild_features": {"type": "array", "items": {"type": "string"}, "description": "Guild feature flags"}, "description": {"type": "string", "description": "Discovery description"}, "category_type": {"type": "number", "description": "Discovery category type"}, - "primary_language": {"description": "Primary community language", "nullable": true, "type": "string"}, + "primary_language": {"nullable": true, "description": "Primary community language", "type": "string"}, "custom_tags": {"type": "array", "items": {"type": "string"}, "description": "Custom discovery tags"}, "applied_at": {"type": "string", "description": "Application timestamp"}, - "approved_at": {"description": "Approval timestamp", "nullable": true, "type": "string"} + "approved_at": {"nullable": true, "description": "Approval timestamp", "type": "string"} }, "required": [ "guild_id", @@ -10949,313 +14501,77 @@ "custom_tags", "applied_at", "approved_at" - ] + ], + "additionalProperties": false }, - "DiscoveryAdminListingBulkCategoryResponse": { - "type": "object", - "properties": { - "updated": {"type": "number", "description": "Number of listings moved"}, - "failed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "description": "Guilds that could not be moved" - } - }, - "required": ["updated", "failed_guild_ids"] - }, - "DiscoveryAdminListingBulkCategoryRequest": { - "type": "object", - "properties": { - "guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "minItems": 1, - "maxItems": 100, - "description": "Listed guilds to move" - }, - "category_type": { - "type": "integer", - "minimum": 0, - "maximum": 8, - "format": "int32", - "description": "Discovery category to file every named guild under" - } - }, - "required": ["guild_ids", "category_type"] - }, - "DiscoveryApplicationPatchRequest": { - "type": "object", - "properties": { - "description": { - "type": "string", - "minLength": 10, - "maxLength": 300, - "description": "Updated description for discovery listing" - }, - "category_type": { - "type": "integer", - "minimum": 0, - "maximum": 8, - "format": "int32", - "description": "Updated discovery category type" - }, - "primary_language": {"type": "string", "description": "Primary community language (BCP-47 code)"}, - "custom_tags": { - "type": "array", - "items": {"type": "string", "minLength": 2, "maxLength": 30}, - "maxItems": 10, - "description": "Up to 10 custom discovery tags" - } - } - }, - "DiscoveryAdminRemoveRequest": { - "type": "object", - "properties": {"reason": {"type": "string", "minLength": 1, "maxLength": 500, "description": "Removal reason"}}, - "required": ["reason"] - }, - "GuildMemoryStatsResponse": { - "type": "object", - "properties": { - "guilds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "node_id": {"type": "string"}, - "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "guild_name": {"type": "string"}, - "guild_icon": {"nullable": true, "type": "string"}, - "nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, - "memory": {"$ref": "#/components/schemas/Int64StringType"}, - "member_count": {"$ref": "#/components/schemas/Int32Type"}, - "session_count": {"$ref": "#/components/schemas/Int32Type"}, - "presence_count": {"$ref": "#/components/schemas/Int32Type"} - }, - "required": [ - "node_id", - "guild_id", - "guild_name", - "guild_icon", - "nsfw_level", - "memory", - "member_count", - "session_count", - "presence_count" - ] - }, - "maxItems": 1000 - } - }, - "required": ["guilds"] - }, - "Int64StringType": {"type": "string", "format": "int64", "pattern": "^-?[0-9]+$"}, - "ReloadAllGuildsResponse": { - "type": "object", - "properties": {"count": {"$ref": "#/components/schemas/Int32Type"}}, - "required": ["count"] - }, - "ReloadGuildsRequest": { - "type": "object", - "properties": { - "guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "List of guild IDs to reload" - } - }, - "required": ["guild_ids"] - }, - "NodeStatsResponse": { - "type": "object", - "properties": { - "status": {"type": "string"}, - "sessions": {"$ref": "#/components/schemas/Int32Type"}, - "guilds": {"$ref": "#/components/schemas/Int32Type"}, - "presences": {"$ref": "#/components/schemas/Int32Type"}, - "calls": {"$ref": "#/components/schemas/Int32Type"}, - "memory": { - "type": "object", - "properties": { - "total": {"$ref": "#/components/schemas/Int64StringType"}, - "processes": {"$ref": "#/components/schemas/Int64StringType"}, - "system": {"$ref": "#/components/schemas/Int64StringType"} - }, - "required": ["total", "processes", "system"] - }, - "process_count": {"$ref": "#/components/schemas/Int32Type"}, - "process_limit": {"$ref": "#/components/schemas/Int32Type"}, - "uptime_seconds": {"$ref": "#/components/schemas/Int32Type"}, - "node_count": {"$ref": "#/components/schemas/Int32Type"}, - "nodes": { - "type": "array", - "items": { - "type": "object", - "properties": { - "node_id": {"type": "string"}, - "status": {"type": "string"}, - "sessions": {"$ref": "#/components/schemas/Int32Type"}, - "guilds": {"$ref": "#/components/schemas/Int32Type"}, - "presences": {"$ref": "#/components/schemas/Int32Type"}, - "calls": {"$ref": "#/components/schemas/Int32Type"}, - "memory": { - "type": "object", - "properties": { - "total": {"$ref": "#/components/schemas/Int64StringType"}, - "processes": {"$ref": "#/components/schemas/Int64StringType"}, - "system": {"$ref": "#/components/schemas/Int64StringType"} - }, - "required": ["total", "processes", "system"] - }, - "process_count": {"$ref": "#/components/schemas/Int32Type"}, - "process_limit": {"$ref": "#/components/schemas/Int32Type"}, - "uptime_seconds": {"$ref": "#/components/schemas/Int32Type"} - }, - "required": [ - "node_id", - "status", - "sessions", - "guilds", - "presences", - "calls", - "memory", - "process_count", - "process_limit", - "uptime_seconds" - ] - }, - "maxItems": 1000 - } - }, - "required": [ - "status", - "sessions", - "guilds", - "presences", - "calls", - "memory", - "process_count", - "process_limit", - "uptime_seconds", - "node_count", - "nodes" - ] - }, - "GatewayVoiceStateCountsResponse": { - "type": "object", - "properties": { - "total_voice_states": {"$ref": "#/components/schemas/Int32Type"}, - "regions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "region_id": {"type": "string"}, - "voice_state_count": {"$ref": "#/components/schemas/Int32Type"} - }, - "required": ["region_id", "voice_state_count"] - }, - "maxItems": 1000 - }, - "servers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "server_id": {"type": "string"}, - "voice_state_count": {"$ref": "#/components/schemas/Int32Type"} - }, - "required": ["server_id", "voice_state_count"] - }, - "maxItems": 5000 - } - }, - "required": ["total_voice_states", "regions", "servers"] - }, - "CodesResponse": { - "type": "object", - "properties": {"codes": {"type": "array", "items": {"type": "string"}}}, - "required": ["codes"] - }, - "GenerateGiftCodesRequest": { - "type": "object", - "properties": { - "count": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "format": "int32", - "description": "Number of gift codes to generate" - }, - "duration_type": { - "type": "string", - "enum": ["days", "weeks", "months", "years"], - "description": "Duration unit for the generated gift codes" - }, - "duration_quantity": { - "type": "integer", - "minimum": 1, - "maximum": 3650, - "format": "int32", - "description": "Duration quantity for the selected unit. Lifetime gifts are not supported." - } - }, - "required": ["count", "duration_type", "duration_quantity"] - }, - "SearchGuildsResponse": { - "type": "object", - "properties": { - "guilds": {"type": "array", "items": {"$ref": "#/components/schemas/GuildAdminResponse"}}, - "total": {"type": "number"} - }, - "required": ["guilds", "total"] + "Int64StringType": {"type": "string", "pattern": "^-?\\d+$", "format": "int64"}, + "GiftCodeDurationTypeSchema": { + "description": "Gift code duration unit", + "x-enumNames": ["days", "weeks", "months", "years"], + "x-enumDescriptions": [ + "Gift duration in days", + "Gift duration in weeks", + "Gift duration in months", + "Gift duration in years" + ], + "enum": ["days", "weeks", "months", "years"], + "type": "string" }, "GuildAdminResponse": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier for this guild" + "description": "The unique identifier for this guild", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "name": {"type": "string", "description": "The name of the guild"}, "features": { - "type": "array", - "items": {"$ref": "#/components/schemas/GuildFeatureSchema"}, "maxItems": 100, + "type": "array", + "items": {"allOf": [{"$ref": "#/components/schemas/GuildFeatureSchema"}]}, "description": "Array of guild feature flags" }, - "owner_id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "The ID of the guild owner"}, - "owner_username": {"description": "The username of the guild owner", "nullable": true, "type": "string"}, + "owner_id": { + "description": "The ID of the guild owner", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "owner_username": {"nullable": true, "description": "The username of the guild owner", "type": "string"}, "owner_global_name": { - "description": "The display name of the guild owner, if set", "nullable": true, + "description": "The display name of the guild owner, if set", "type": "string" }, "owner_discriminator": { - "description": "The discriminator of the guild owner", "nullable": true, + "description": "The discriminator of the guild owner", "type": "string" }, - "icon": {"description": "The hash of the guild icon", "nullable": true, "type": "string"}, - "banner": {"description": "The hash of the guild banner", "nullable": true, "type": "string"}, + "icon": {"nullable": true, "description": "The hash of the guild icon", "type": "string"}, + "banner": {"nullable": true, "description": "The hash of the guild banner", "type": "string"}, "member_count": { - "type": "integer", - "minimum": 0, - "maximum": 2147483647, - "format": "int32", - "description": "The number of members in the guild" + "description": "The number of members in the guild", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "nsfw_level": {"allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, + "nsfw": {"description": "Whether the guild is flagged as adult content", "type": "boolean"}, + "content_warning_level": { + "description": "The content warning level for the guild", + "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] }, - "nsfw_level": {"$ref": "#/components/schemas/NSFWLevel"}, - "nsfw": {"type": "boolean", "description": "Whether the guild is flagged as adult content"}, - "content_warning_level": {"$ref": "#/components/schemas/ContentWarningLevel"}, "content_warning_text": { "description": "Custom content warning text shown before entry", "nullable": true, - "type": "string" + "type": "string", + "maxLength": 200 }, - "approximate_member_count": {"$ref": "#/components/schemas/Int32Type"}, - "approximate_presence_count": {"$ref": "#/components/schemas/Int32Type"} + "approximate_member_count": { + "description": "Approximate total member count (only when with_counts is true)", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + }, + "approximate_presence_count": { + "description": "Approximate online member count (only when with_counts is true)", + "allOf": [{"$ref": "#/components/schemas/Int32Type"}] + } }, "required": [ "id", @@ -11268,382 +14584,336 @@ "icon", "banner", "member_count" - ] + ], + "additionalProperties": false }, - "LookupGuildResponse": { - "type": "object", - "properties": { - "guild": { - "nullable": true, - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "owner_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "owner_username": {"nullable": true, "type": "string"}, - "owner_global_name": {"nullable": true, "type": "string"}, - "owner_discriminator": {"nullable": true, "type": "string"}, - "name": {"type": "string"}, - "vanity_url_code": {"nullable": true, "type": "string"}, - "icon": {"nullable": true, "type": "string"}, - "banner": {"nullable": true, "type": "string"}, - "splash": {"nullable": true, "type": "string"}, - "embed_splash": {"nullable": true, "type": "string"}, - "features": {"type": "array", "items": {"type": "string"}, "maxItems": 100}, - "verification_level": {"$ref": "#/components/schemas/GuildVerificationLevel"}, - "mfa_level": {"$ref": "#/components/schemas/GuildMFALevel"}, - "nsfw_level": {"$ref": "#/components/schemas/NSFWLevel"}, - "nsfw": {"type": "boolean"}, - "content_warning_level": {"$ref": "#/components/schemas/ContentWarningLevel"}, - "content_warning_text": {"nullable": true, "type": "string"}, - "explicit_content_filter": {"$ref": "#/components/schemas/GuildExplicitContentFilter"}, - "default_message_notifications": {"$ref": "#/components/schemas/DefaultMessageNotifications"}, - "afk_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "afk_timeout": {"$ref": "#/components/schemas/Int32Type"}, - "system_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "system_channel_flags": {"$ref": "#/components/schemas/SystemChannelFlags"}, - "rules_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "disabled_operations": {"$ref": "#/components/schemas/Int32Type"}, - "member_count": {"$ref": "#/components/schemas/Int32Type"}, - "channels": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"nullable": true, "type": "string"}, - "type": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4, 998, 999], - "description": "The type of the channel" - }, - "position": {"$ref": "#/components/schemas/Int32Type"}, - "parent_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "nsfw": {"nullable": true, "type": "boolean"}, - "nsfw_override": {"nullable": true, "type": "boolean"}, - "content_warning_level": {"$ref": "#/components/schemas/ContentWarningLevel"}, - "content_warning_text": {"nullable": true, "type": "string"}, - "url": {"nullable": true, "type": "string"} - }, - "required": ["id", "name", "type", "position", "parent_id", "nsfw", "url"] - } - }, - "roles": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"type": "string"}, - "color": {"$ref": "#/components/schemas/Int32Type"}, - "position": {"$ref": "#/components/schemas/Int32Type"}, - "permissions": { - "type": "string", - "format": "int64", - "pattern": "^[0-9]+$", - "description": "The role permissions bitfield" - }, - "hoist": {"type": "boolean"}, - "mentionable": {"type": "boolean"} - }, - "required": ["id", "name", "color", "position", "permissions", "hoist", "mentionable"] - } - } - }, - "required": [ - "id", - "owner_id", - "owner_username", - "owner_global_name", - "owner_discriminator", - "name", - "vanity_url_code", - "icon", - "banner", - "splash", - "embed_splash", - "features", - "verification_level", - "mfa_level", - "nsfw_level", - "explicit_content_filter", - "default_message_notifications", - "afk_channel_id", - "afk_timeout", - "system_channel_id", - "system_channel_flags", - "rules_channel_id", - "disabled_operations", - "member_count", - "channels", - "roles" - ] + "Permissions": { + "type": "string", + "pattern": "^\\d+$", + "description": "Permission bitfield as string", + "format": "int64", + "x-bitflagValues": [ + {"name": "CREATE_INSTANT_INVITE", "value": "1", "description": "Allows creation of instant invites"}, + {"name": "KICK_MEMBERS", "value": "2", "description": "Allows kicking members from the guild"}, + {"name": "BAN_MEMBERS", "value": "4", "description": "Allows banning members from the guild"}, + { + "name": "ADMINISTRATOR", + "value": "8", + "description": "Grants all permissions and bypasses channel permission overwrites" + }, + { + "name": "MANAGE_CHANNELS", + "value": "16", + "description": "Allows management, editing, and deletion of channels" + }, + {"name": "MANAGE_GUILD", "value": "32", "description": "Allows management and editing of the guild"}, + {"name": "ADD_REACTIONS", "value": "64", "description": "Allows adding reactions to messages"}, + {"name": "VIEW_AUDIT_LOG", "value": "128", "description": "Allows viewing of the audit log"}, + { + "name": "PRIORITY_SPEAKER", + "value": "256", + "description": "Allows using priority speaker in a voice channel" + }, + {"name": "STREAM", "value": "512", "description": "Allows the user to go live"}, + {"name": "VIEW_CHANNEL", "value": "1024", "description": "Allows viewing a channel"}, + {"name": "SEND_MESSAGES", "value": "2048", "description": "Allows sending messages in a channel"}, + {"name": "SEND_TTS_MESSAGES", "value": "4096", "description": "Allows sending text-to-speech messages"}, + {"name": "MANAGE_MESSAGES", "value": "8192", "description": "Allows for deleting and pinning messages"}, + {"name": "EMBED_LINKS", "value": "16384", "description": "Links sent will have an embed automatically"}, + {"name": "ATTACH_FILES", "value": "32768", "description": "Allows uploading files"}, + {"name": "READ_MESSAGE_HISTORY", "value": "65536", "description": "Allows reading message history"}, + {"name": "MENTION_EVERYONE", "value": "131072", "description": "Allows using @everyone and @here mentions"}, + {"name": "USE_EXTERNAL_EMOJIS", "value": "262144", "description": "Allows using emojis from other guilds"}, + {"name": "CONNECT", "value": "1048576", "description": "Allows connecting to a voice channel"}, + {"name": "SPEAK", "value": "2097152", "description": "Allows speaking in a voice channel"}, + {"name": "MUTE_MEMBERS", "value": "4194304", "description": "Allows muting members in voice channels"}, + {"name": "DEAFEN_MEMBERS", "value": "8388608", "description": "Allows deafening members in voice channels"}, + {"name": "MOVE_MEMBERS", "value": "16777216", "description": "Allows moving members between voice channels"}, + {"name": "USE_VAD", "value": "33554432", "description": "Allows using voice activity detection"}, + {"name": "CHANGE_NICKNAME", "value": "67108864", "description": "Allows changing own nickname"}, + {"name": "MANAGE_NICKNAMES", "value": "134217728", "description": "Allows changing other members nicknames"}, + {"name": "MANAGE_ROLES", "value": "268435456", "description": "Allows management and editing of roles"}, + {"name": "MANAGE_WEBHOOKS", "value": "536870912", "description": "Allows management and editing of webhooks"}, + { + "name": "MANAGE_EXPRESSIONS", + "value": "1073741824", + "description": "Allows management of guild expressions" + }, + { + "name": "USE_EXTERNAL_STICKERS", + "value": "137438953472", + "description": "Allows using stickers from other guilds" + }, + {"name": "MODERATE_MEMBERS", "value": "1099511627776", "description": "Allows timing out users"}, + {"name": "CREATE_EXPRESSIONS", "value": "8796093022208", "description": "Allows creating guild expressions"}, + {"name": "PIN_MESSAGES", "value": "2251799813685248", "description": "Allows pinning messages"}, + {"name": "BYPASS_SLOWMODE", "value": "4503599627370496", "description": "Allows bypassing slowmode"}, + {"name": "UPDATE_RTC_REGION", "value": "9007199254740992", "description": "Allows updating the voice region"}, + { + "name": "VIEW_CHANNEL_MEMBERS", + "value": "18014398509481984", + "description": "Allows viewing the member list in a channel" } - }, - "required": ["guild"] - }, - "GuildVerificationLevel": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2, 3, 4], - "description": "Required verification level for members" - }, - "GuildMFALevel": { - "type": "integer", - "format": "int32", - "enum": [0, 1], - "description": "Required MFA level for moderation actions" - }, - "GuildExplicitContentFilter": { - "type": "integer", - "format": "int32", - "enum": [0, 1, 2], - "description": "Level of content filtering for explicit media" - }, - "DefaultMessageNotifications": { - "type": "integer", - "format": "int32", - "enum": [0, 1], - "description": "Default notification level for new members" + ] }, "SystemChannelFlags": { "type": "integer", - "format": "int32", "minimum": 0, "maximum": 2147483647, - "description": "System channel message flags" - }, - "GuildUpdateResponse": { - "type": "object", - "properties": { - "guild": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"type": "string"}, - "features": {"type": "array", "items": {"type": "string"}, "maxItems": 100}, - "owner_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "icon": {"nullable": true, "type": "string"}, - "banner": {"nullable": true, "type": "string"}, - "member_count": {"$ref": "#/components/schemas/Int32Type"}, - "nsfw_level": {"$ref": "#/components/schemas/NSFWLevel"}, - "nsfw": {"type": "boolean"}, - "content_warning_level": {"$ref": "#/components/schemas/ContentWarningLevel"}, - "content_warning_text": {"nullable": true, "type": "string"} - }, - "required": ["id", "name", "features", "owner_id", "icon", "banner", "member_count"] + "description": "System channel message flags", + "format": "int32", + "x-bitflagValues": [ + { + "name": "SUPPRESS_JOIN_NOTIFICATIONS", + "value": "1", + "description": "Suppress member join notifications in system channel" } - }, - "required": ["guild"] + ] }, - "UpdateGuildRequest": { - "type": "object", - "properties": { - "verification_level": { - "$ref": "#/components/schemas/GuildVerificationLevel", - "description": "Required verification level for guild members" - }, - "mfa_level": { - "$ref": "#/components/schemas/GuildMFALevel", - "description": "Required MFA level for moderators" - }, - "nsfw_level": {"$ref": "#/components/schemas/NSFWLevel", "description": "NSFW content level for the guild"}, - "nsfw": {"type": "boolean", "description": "Whether the guild is flagged as adult content"}, - "content_warning_level": {"$ref": "#/components/schemas/ContentWarningLevel"}, - "content_warning_text": { - "description": "Custom content warning text shown before entry", - "nullable": true, - "type": "string" - }, - "explicit_content_filter": { - "$ref": "#/components/schemas/GuildExplicitContentFilter", - "description": "Explicit content filter level" - }, - "default_message_notifications": { - "$ref": "#/components/schemas/DefaultMessageNotifications", - "description": "Default notification setting for new members" - }, - "disabled_operations": {"$ref": "#/components/schemas/GuildOperations"}, - "name": {"type": "string", "description": "New name for the guild"}, - "vanity_url_code": { - "description": "New vanity URL code, or null to remove", - "nullable": true, - "type": "string" - }, - "new_owner_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "add_features": { - "type": "array", - "items": {"$ref": "#/components/schemas/GuildFeatureSchema"}, - "maxItems": 100 - }, - "remove_features": { - "type": "array", - "items": {"$ref": "#/components/schemas/GuildFeatureSchema"}, - "maxItems": 100 - }, - "fields": { - "type": "array", - "items": { - "type": "string", - "enum": ["icon", "banner", "splash", "embed_splash"], - "description": "Guild image field that can be cleared" - }, - "maxItems": 10, - "description": "List of guild image fields to clear" - } - } + "DefaultMessageNotifications": { + "description": "Default notification level for new members", + "type": "integer", + "enum": [0, 1], + "format": "int32", + "x-enumNames": ["ALL_MESSAGES", "ONLY_MENTIONS"], + "x-enumDescriptions": ["Notify on all messages", "Notify only on mentions"] + }, + "GuildExplicitContentFilter": { + "description": "Level of content filtering for explicit media", + "type": "integer", + "enum": [0, 1, 2], + "format": "int32", + "x-enumNames": ["DISABLED", "MEMBERS_WITHOUT_ROLES", "ALL_MEMBERS"], + "x-enumDescriptions": [ + "Media content will not be scanned", + "Media content from members without roles will be scanned", + "Media content from all members will be scanned" + ] + }, + "GuildMFALevel": { + "description": "Required MFA level for moderation actions", + "type": "integer", + "enum": [0, 1], + "format": "int32", + "x-enumNames": ["NONE", "ELEVATED"], + "x-enumDescriptions": ["Guild has no MFA requirement", "Guild requires 2FA for moderation actions"] + }, + "GuildVerificationLevel": { + "description": "Required verification level for members", + "type": "integer", + "enum": [0, 1, 2, 3, 4], + "format": "int32", + "x-enumNames": ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"], + "x-enumDescriptions": [ + "Unrestricted", + "Must have verified email", + "Registered for more than 5 minutes", + "Member of the server for more than 10 minutes", + "Must have a verified phone number" + ] }, "GuildOperations": { "type": "integer", - "format": "int32", "minimum": 0, "maximum": 2147483647, - "description": "Bitmask of disabled guild operations" + "description": "Bitmask of disabled guild operations", + "format": "int32", + "x-bitflagValues": [ + {"name": "PUSH_NOTIFICATIONS", "value": "1", "description": "Allow push notifications for this guild"}, + {"name": "EVERYONE_MENTIONS", "value": "2", "description": "Allow @everyone mentions in this guild"}, + {"name": "TYPING_EVENTS", "value": "4", "description": "Enable typing indicator events"}, + {"name": "INSTANT_INVITES", "value": "8", "description": "Allow creation of instant invites"}, + {"name": "SEND_MESSAGE", "value": "16", "description": "Allow sending messages in the guild"}, + {"name": "REACTIONS", "value": "32", "description": "Allow adding reactions to messages"}, + {"name": "MEMBER_LIST_UPDATES", "value": "64", "description": "Enable member list update events"} + ] }, - "SuccessResponse": { + "DefaultMessageNotificationsInput": { + "description": "Default notification level for new members", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": ["ALL_MESSAGES", "ONLY_MENTIONS"], + "x-enumDescriptions": ["Notify on all messages", "Notify only on mentions"], + "enum": [0, 1] + }, + "GuildExplicitContentFilterInput": { + "description": "Level of content filtering for explicit media", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": ["DISABLED", "MEMBERS_WITHOUT_ROLES", "ALL_MEMBERS"], + "x-enumDescriptions": [ + "Media content will not be scanned", + "Media content from members without roles will be scanned", + "Media content from all members will be scanned" + ], + "enum": [0, 1, 2] + }, + "ContentWarningLevelInput": { + "description": "The content warning level for a guild, category, or channel", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": ["INHERIT", "CONTENT_WARNING"], + "x-enumDescriptions": [ + "No level set on this scope; channels and categories inherit from parent", + "Show a content warning before entering" + ], + "enum": [0, 1] + }, + "NSFWLevelInput": { + "description": "The NSFW level of the guild", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": ["SAFE", "AGE_RESTRICTED"], + "x-enumDescriptions": ["Guild is safe for all ages", "Guild is age-restricted"], + "enum": [0, 3] + }, + "GuildMFALevelInput": { + "description": "Required MFA level for moderation actions", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": ["NONE", "ELEVATED"], + "x-enumDescriptions": ["Guild has no MFA requirement", "Guild requires 2FA for moderation actions"], + "enum": [0, 1] + }, + "GuildVerificationLevelInput": { + "description": "Required verification level for members", + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "format": "int32", + "x-enumNames": ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"], + "x-enumDescriptions": [ + "Unrestricted", + "Must have verified email", + "Registered for more than 5 minutes", + "Member of the server for more than 10 minutes", + "Must have a verified phone number" + ], + "enum": [0, 1, 2, 3, 4] + }, + "PurgeGuildAssetErrorSchema": { "type": "object", "properties": { - "success": {"type": "boolean", "enum": [true], "description": "Whether the operation succeeded"} + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, + "error": {"type": "string", "minLength": 1, "maxLength": 4000} }, - "required": ["success"] - }, - "AdminArchiveCreateRequest": { - "type": "object", - "properties": { - "include_attachments": { - "type": "boolean", - "description": "Whether to include attachment binaries in the archive" - } - } - }, - "PurgeGuildAssetsResponseSchema": { - "type": "object", - "properties": { - "processed": {"type": "array", "items": {"$ref": "#/components/schemas/PurgeGuildAssetResultSchema"}}, - "errors": {"type": "array", "items": {"$ref": "#/components/schemas/PurgeGuildAssetErrorSchema"}} - }, - "required": ["processed", "errors"] + "required": ["id", "error"], + "additionalProperties": false }, "PurgeGuildAssetResultSchema": { "type": "object", "properties": { - "id": {"type": "string", "pattern": "^(0|[1-9][0-9]*)$", "description": "Unique identifier of the asset"}, + "id": { + "description": "Unique identifier of the asset", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, "asset_type": { - "type": "string", + "description": "Type of guild asset", + "x-enumNames": ["emoji", "sticker", "unknown"], + "x-enumDescriptions": ["Custom emoji asset", "Custom sticker asset", "Unknown asset type"], "enum": ["emoji", "sticker", "unknown"], - "description": "Type of guild asset" + "type": "string" }, "found_in_db": {"type": "boolean", "description": "Whether the asset was found in the database"}, "guild_id": { - "description": "ID of the guild the asset belongs to", "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + "description": "ID of the guild the asset belongs to", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "guild_nsfw_level": { - "description": "NSFW level of the guild the asset belongs to", "nullable": true, + "description": "NSFW level of the guild the asset belongs to", "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}] } }, - "required": ["id", "asset_type", "found_in_db", "guild_id", "guild_nsfw_level"] + "required": ["id", "asset_type", "found_in_db", "guild_id", "guild_nsfw_level"], + "additionalProperties": false }, - "PurgeGuildAssetErrorSchema": { - "type": "object", - "properties": {"id": {"$ref": "#/components/schemas/SnowflakeType"}, "error": {"type": "string"}}, - "required": ["id", "error"] - }, - "PurgeGuildAssetsRequest": { + "AuditLogWebhookResponse": { "type": "object", "properties": { - "ids": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "List of asset IDs to purge" - } - }, - "required": ["ids"] - }, - "ListGuildAuditLogsResponse": { - "type": "object", - "properties": { - "audit_log_entries": { - "type": "array", - "items": {"$ref": "#/components/schemas/GuildAuditLogEntryResponse"}, - "description": "Array of audit log entries" + "id": { + "description": "The unique identifier for this webhook", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "users": { - "type": "array", - "items": {"$ref": "#/components/schemas/UserPartialResponse"}, - "description": "Users referenced in the audit log entries" + "type": {"allOf": [{"$ref": "#/components/schemas/WebhookType"}]}, + "guild_id": { + "description": "The guild ID this webhook belongs to", + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "webhooks": { - "type": "array", - "items": {"$ref": "#/components/schemas/AuditLogWebhookResponse"}, - "description": "Webhooks referenced in the audit log entries" - } + "channel_id": { + "description": "The channel ID this webhook posts to", + "nullable": true, + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] + }, + "name": {"type": "string", "description": "The name of the webhook"}, + "avatar_hash": {"description": "The hash of the webhook avatar", "nullable": true, "type": "string"} }, - "required": ["audit_log_entries", "users", "webhooks"] + "required": ["id", "type", "name"], + "additionalProperties": false }, "GuildAuditLogEntryResponse": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier for this audit log entry" + "description": "The unique identifier for this audit log entry", + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, - "action_type": {"$ref": "#/components/schemas/AuditLogActionType"}, + "action_type": {"allOf": [{"$ref": "#/components/schemas/AuditLogActionType"}]}, "user_id": { "description": "The user ID of the user who performed the action", "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] + "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}] }, "target_id": { "description": "The ID of the affected entity (user, channel, role, invite code, etc.)", "nullable": true, "type": "string" }, - "reason": {"type": "string", "description": "The reason provided for the action"}, + "reason": {"description": "The reason provided for the action", "type": "string"}, "options": { + "description": "Additional options depending on action type", "type": "object", "properties": { - "channel_id": {"type": "string", "description": "Channel ID for relevant actions"}, - "count": {"type": "number", "description": "Count of items affected"}, + "channel_id": {"description": "Channel ID for relevant actions", "type": "string"}, + "count": {"description": "Count of items affected", "type": "number"}, "delete_member_days": { - "type": "string", - "description": "Number of days of messages to delete on member ban" + "description": "Number of days of messages to delete on member ban", + "type": "string" }, - "id": {"type": "string", "description": "ID of the affected entity"}, - "integration_type": {"type": "number", "description": "Type of integration"}, - "message_id": {"type": "string", "description": "Message ID for relevant actions"}, - "members_removed": {"type": "number", "description": "Number of members removed"}, - "role_name": {"type": "string", "description": "Name of the role"}, - "type": {"type": "number", "description": "Type identifier"}, - "inviter_id": {"type": "string", "description": "ID of the user who created the invite"}, - "max_age": {"type": "number", "description": "Maximum age of the invite in seconds"}, - "max_uses": {"type": "number", "description": "Maximum number of uses for the invite"}, - "temporary": {"type": "boolean", "description": "Whether the invite grants temporary membership"}, - "uses": {"type": "number", "description": "Number of times the invite has been used"} + "id": {"description": "ID of the affected entity", "type": "string"}, + "integration_type": {"description": "Type of integration", "type": "number"}, + "message_id": {"description": "Message ID for relevant actions", "type": "string"}, + "members_removed": {"description": "Number of members removed", "type": "number"}, + "role_name": {"description": "Name of the role", "type": "string"}, + "type": {"description": "Type identifier", "type": "number"}, + "inviter_id": {"description": "ID of the user who created the invite", "type": "string"}, + "max_age": {"description": "Maximum age of the invite in seconds", "type": "number"}, + "max_uses": {"description": "Maximum number of uses for the invite", "type": "number"}, + "temporary": {"description": "Whether the invite grants temporary membership", "type": "boolean"}, + "uses": {"description": "Number of times the invite has been used", "type": "number"} }, - "description": "Additional options depending on action type" + "additionalProperties": false }, "changes": { + "description": "Changes made to the target", "type": "array", - "items": {"$ref": "#/components/schemas/AuditLogChangeSchema"}, - "description": "Changes made to the target" + "items": {"$ref": "#/components/schemas/AuditLogChangeSchema"} } }, - "required": ["id", "action_type"] - }, - "AuditLogActionType": { - "type": "integer", - "format": "int32", - "enum": [ - 1, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 40, 41, 42, 50, 51, 52, 60, 61, 62, - 90, 91, 92, 72, 73, 74, 75 - ], - "description": "The type of action that occurred" + "required": ["id", "action_type"], + "additionalProperties": false }, "AuditLogChangeSchema": { "type": "object", @@ -11651,8 +14921,7 @@ "key": {"type": "string", "description": "The field that changed"}, "old_value": { "description": "Value before the change", - "nullable": true, - "oneOf": [ + "anyOf": [ {"type": "string"}, {"type": "number"}, {"type": "boolean"}, @@ -11664,14 +14933,15 @@ "added": {"type": "array", "items": {"type": "string"}}, "removed": {"type": "array", "items": {"type": "string"}} }, - "required": ["added", "removed"] - } + "required": ["added", "removed"], + "additionalProperties": false + }, + {"type": "string", "nullable": true, "enum": [null]} ] }, "new_value": { "description": "Value after the change", - "nullable": true, - "oneOf": [ + "anyOf": [ {"type": "string"}, {"type": "number"}, {"type": "boolean"}, @@ -11683,98 +14953,114 @@ "added": {"type": "array", "items": {"type": "string"}}, "removed": {"type": "array", "items": {"type": "string"}} }, - "required": ["added", "removed"] - } + "required": ["added", "removed"], + "additionalProperties": false + }, + {"type": "string", "nullable": true, "enum": [null]} ] } }, - "required": ["key"] + "required": ["key"], + "additionalProperties": false }, - "AuditLogWebhookResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^(0|[1-9][0-9]*)$", - "description": "The unique identifier for this webhook" - }, - "type": {"$ref": "#/components/schemas/WebhookType"}, - "guild_id": { - "description": "The guild ID this webhook belongs to", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] - }, - "channel_id": { - "description": "The channel ID this webhook posts to", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] - }, - "name": {"type": "string", "description": "The name of the webhook"}, - "avatar_hash": {"description": "The hash of the webhook avatar", "nullable": true, "type": "string"} - }, - "required": ["id", "type", "name"] + "AuditLogActionType": { + "description": "The type of action that occurred", + "type": "integer", + "enum": [ + 1, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 40, 41, 42, 50, 51, 52, 60, 61, 62, + 90, 91, 92, 72, 73, 74, 75 + ], + "format": "int32", + "x-enumNames": [ + "GUILD_UPDATE", + "CHANNEL_CREATE", + "CHANNEL_UPDATE", + "CHANNEL_DELETE", + "CHANNEL_OVERWRITE_CREATE", + "CHANNEL_OVERWRITE_UPDATE", + "CHANNEL_OVERWRITE_DELETE", + "MEMBER_KICK", + "MEMBER_PRUNE", + "MEMBER_BAN_ADD", + "MEMBER_BAN_REMOVE", + "MEMBER_UPDATE", + "MEMBER_ROLE_UPDATE", + "MEMBER_MOVE", + "MEMBER_DISCONNECT", + "BOT_ADD", + "ROLE_CREATE", + "ROLE_UPDATE", + "ROLE_DELETE", + "INVITE_CREATE", + "INVITE_UPDATE", + "INVITE_DELETE", + "WEBHOOK_CREATE", + "WEBHOOK_UPDATE", + "WEBHOOK_DELETE", + "EMOJI_CREATE", + "EMOJI_UPDATE", + "EMOJI_DELETE", + "STICKER_CREATE", + "STICKER_UPDATE", + "STICKER_DELETE", + "MESSAGE_DELETE", + "MESSAGE_BULK_DELETE", + "MESSAGE_PIN", + "MESSAGE_UNPIN" + ], + "x-enumDescriptions": [ + "Guild settings were updated", + "Channel was created", + "Channel was updated", + "Channel was deleted", + "Permission overwrite was created", + "Permission overwrite was updated", + "Permission overwrite was deleted", + "Member was kicked", + "Members were pruned", + "Member was banned", + "Member ban was removed", + "Member was updated", + "Member roles were updated", + "Member was moved to a different voice channel", + "Member was disconnected from a voice channel", + "Bot was added to the guild", + "Role was created", + "Role was updated", + "Role was deleted", + "Invite was created", + "Invite was updated", + "Invite was deleted", + "Webhook was created", + "Webhook was updated", + "Webhook was deleted", + "Emoji was created", + "Emoji was updated", + "Emoji was deleted", + "Sticker was created", + "Sticker was updated", + "Sticker was deleted", + "Message was deleted", + "Messages were bulk deleted", + "Message was pinned", + "Message was unpinned" + ] }, - "WebhookType": {"type": "integer", "format": "int32", "enum": [1, 2], "description": "The type of webhook"}, - "BanGuildMemberBody": { - "type": "object", - "properties": { - "delete_message_days": { - "type": "integer", - "minimum": 0, - "maximum": 7, - "format": "int32", - "description": "Number of days of messages to delete from the banned user (0-7). Deprecated in favor of delete_message_seconds." - }, - "delete_message_seconds": { - "type": "integer", - "minimum": 0, - "maximum": 604800, - "format": "int32", - "description": "Number of seconds of messages to delete for the banned user (0-604800, default 0)" - }, - "reason": {"description": "The reason for the ban (max 512 characters)", "nullable": true, "type": "string"}, - "ban_duration_seconds": { - "type": "integer", - "format": "int53", - "description": "Duration of the ban in seconds (0 for permanent, or between 60 and 63072000 seconds for a temporary ban)" - } - } - }, - "ListGuildEmojisResponse": { - "type": "object", - "properties": { - "guild_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "emojis": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"type": "string"}, - "animated": {"type": "boolean"}, - "creator_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "media_url": {"type": "string"} - }, - "required": ["id", "name", "animated", "creator_id", "media_url"] - } - } - }, - "required": ["guild_id", "emojis"] - }, - "ListGuildMembersResponse": { - "type": "object", - "properties": { - "members": {"type": "array", "items": {"$ref": "#/components/schemas/GuildMemberResponse"}}, - "total": {"$ref": "#/components/schemas/Int32Type"}, - "limit": {"$ref": "#/components/schemas/Int32Type"}, - "offset": {"$ref": "#/components/schemas/Int32Type"} - }, - "required": ["members", "total", "limit", "offset"] + "WebhookType": { + "description": "The type of webhook", + "type": "integer", + "enum": [1, 2], + "format": "int32", + "x-enumNames": ["INCOMING", "CHANNEL_FOLLOWER"], + "x-enumDescriptions": ["Incoming webhook", "Channel follower webhook"] }, "GuildMemberResponse": { "type": "object", "properties": { - "user": {"$ref": "#/components/schemas/UserPartialResponse"}, + "user": { + "description": "The user this guild member represents", + "allOf": [{"$ref": "#/components/schemas/UserPartialResponse"}] + }, "nick": {"description": "The nickname of the member in this guild", "nullable": true, "type": "string"}, "avatar": {"description": "The hash of the member guild-specific avatar", "nullable": true, "type": "string"}, "banner": {"description": "The hash of the member guild-specific banner", "nullable": true, "type": "string"}, @@ -11784,14 +15070,15 @@ "allOf": [{"$ref": "#/components/schemas/Int32Type"}] }, "roles": { + "maxItems": 250, "type": "array", "items": {"type": "string"}, - "maxItems": 250, "description": "Array of role IDs the member has" }, "joined_at": { "type": "string", "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO8601 timestamp of when the user joined the guild" }, "mute": {"type": "boolean", "description": "Whether the member is muted in voice channels"}, @@ -11800,965 +15087,214 @@ "description": "ISO8601 timestamp until which the member is timed out", "nullable": true, "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "profile_flags": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/GuildMemberProfileFlags"}]}, "mention_flags": { "nullable": true, - "allOf": [ - { - "$ref": "#/components/schemas/MentionReplyPreferences", - "description": "Per-guild reply mention preference override; NO_PREFERENCE means inherit the user-level mention_flags." - } - ] + "description": "Per-guild reply mention preference override; NO_PREFERENCE means inherit the user-level mention_flags.", + "allOf": [{"$ref": "#/components/schemas/MentionReplyPreferences"}] } }, - "required": ["user", "roles", "joined_at", "mute", "deaf"] + "required": ["user", "roles", "joined_at", "mute", "deaf"], + "additionalProperties": false }, "GuildMemberProfileFlags": { "type": "integer", - "format": "int32", "minimum": 0, "maximum": 2147483647, - "description": "Member profile flags" - }, - "ListGuildStickersResponse": { - "type": "object", - "properties": { - "guild_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "stickers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "name": {"type": "string"}, - "animated": {"type": "boolean"}, - "creator_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "media_url": {"type": "string"} - }, - "required": ["id", "name", "animated", "creator_id", "media_url"] - } - } - }, - "required": ["guild_id", "stickers"] - }, - "InstanceConfigResponse": { - "type": "object", - "properties": { - "sso": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "enforced": {"type": "boolean"}, - "display_name": {"nullable": true, "type": "string"}, - "issuer": {"nullable": true, "type": "string"}, - "authorization_url": {"nullable": true, "type": "string"}, - "token_url": {"nullable": true, "type": "string"}, - "userinfo_url": {"nullable": true, "type": "string"}, - "jwks_url": {"nullable": true, "type": "string"}, - "client_id": {"nullable": true, "type": "string"}, - "client_secret_set": {"type": "boolean"}, - "scope": {"nullable": true, "type": "string"}, - "allowed_domains": {"type": "array", "items": {"type": "string"}, "maxItems": 100}, - "auto_provision": {"type": "boolean"}, - "redirect_uri": {"nullable": true, "type": "string"} - }, - "required": [ - "enabled", - "enforced", - "display_name", - "issuer", - "authorization_url", - "token_url", - "userinfo_url", - "jwks_url", - "client_id", - "client_secret_set", - "scope", - "allowed_domains", - "auto_provision", - "redirect_uri" - ] - }, - "gateway_rollout": {"$ref": "#/components/schemas/GatewayRolloutConfigSchema"}, - "voice_noise_suppression": {"$ref": "#/components/schemas/VoiceNoiseSuppressionConfigSchema"}, - "experiment_delivery": {"$ref": "#/components/schemas/ExperimentDeliveryConfigSchema"}, - "registration": { - "type": "object", - "properties": { - "mode": {"type": "string", "enum": ["open", "approval", "closed"], "description": "Registration mode"}, - "admin_registration_urls_enabled": {"type": "boolean"}, - "urls": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"type": "string"}, - "label": {"nullable": true, "type": "string"}, - "created_by_user_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "created_at": {"type": "string", "format": "date-time"}, - "expires_at": {"nullable": true, "type": "string", "format": "date-time"}, - "max_uses": { - "nullable": true, - "type": "integer", - "minimum": 1, - "maximum": 9007199254740991, - "format": "int53" - }, - "use_count": {"type": "integer", "minimum": 0, "maximum": 9007199254740991, "format": "int53"}, - "revoked_at": {"nullable": true, "type": "string", "format": "date-time"}, - "approval_required": {"type": "boolean"}, - "last_used_at": {"nullable": true, "type": "string", "format": "date-time"}, - "last_used_by_user_id": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}] - } - }, - "required": [ - "id", - "label", - "created_by_user_id", - "created_at", - "expires_at", - "max_uses", - "use_count", - "revoked_at", - "approval_required", - "last_used_at", - "last_used_by_user_id" - ] - } - }, - "pending_registrations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "user_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "username": {"type": "string"}, - "discriminator": {"type": "integer", "minimum": 0, "maximum": 9999, "format": "int32"}, - "global_name": {"nullable": true, "type": "string"}, - "email": {"nullable": true, "type": "string"}, - "requested_at": {"type": "string", "format": "date-time"}, - "registration_url_id": {"nullable": true, "type": "string"}, - "client_ip": {"nullable": true, "type": "string"} - }, - "required": [ - "user_id", - "username", - "discriminator", - "global_name", - "email", - "requested_at", - "registration_url_id", - "client_ip" - ] - } - } - }, - "required": ["mode", "admin_registration_urls_enabled", "urls", "pending_registrations"] - }, - "self_hosted": {"type": "boolean"}, - "app_public": { - "type": "object", - "properties": { - "branding": { - "type": "object", - "properties": { - "product_name": {"type": "string"}, - "icon_url": {"nullable": true, "type": "string"}, - "symbol_url": {"nullable": true, "type": "string"}, - "logo_url": {"nullable": true, "type": "string"}, - "wordmark_url": {"nullable": true, "type": "string"}, - "favicon_url": {"nullable": true, "type": "string"}, - "theme_color": {"nullable": true, "type": "string"} - }, - "required": [ - "product_name", - "icon_url", - "symbol_url", - "logo_url", - "wordmark_url", - "favicon_url", - "theme_color" - ] - }, - "setup": { - "type": "object", - "properties": {"configured": {"type": "boolean"}}, - "required": ["configured"] - }, - "legal": { - "type": "object", - "properties": { - "terms_url": {"nullable": true, "type": "string"}, - "privacy_url": {"nullable": true, "type": "string"} - }, - "required": ["terms_url", "privacy_url"] - }, - "registration": { - "type": "object", - "properties": {"collect_date_of_birth": {"type": "boolean"}}, - "required": ["collect_date_of_birth"] - } - }, - "required": ["branding", "setup", "legal", "registration"] - }, - "policy": { - "type": "object", - "properties": { - "single_community_enabled": {"type": "boolean"}, - "single_community_guild_id": {"nullable": true, "type": "string"}, - "direct_messages_disabled": {"type": "boolean"}, - "direct_messages_locked": {"type": "boolean"}, - "premium_mode": {"enum": ["mirror", "everyone"], "type": "string"}, - "services": { - "type": "object", - "properties": { - "gif_enabled": {"nullable": true, "type": "boolean"}, - "youtube_enabled": {"nullable": true, "type": "boolean"}, - "bluesky_enabled": {"nullable": true, "type": "boolean"} - }, - "required": ["gif_enabled", "youtube_enabled", "bluesky_enabled"] - }, - "services_resolved": { - "type": "object", - "properties": { - "gif_enabled": {"type": "boolean"}, - "youtube_enabled": {"type": "boolean"}, - "bluesky_enabled": {"type": "boolean"} - }, - "required": ["gif_enabled", "youtube_enabled", "bluesky_enabled"] - }, - "services_available": { - "type": "object", - "properties": { - "gif": {"type": "boolean"}, - "youtube": {"type": "boolean"}, - "bluesky": {"type": "boolean"} - }, - "required": ["gif", "youtube", "bluesky"] - }, - "deferred_phone_gate": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "window_hours": {"type": "number"}, - "member_threshold": {"type": "number"} - }, - "required": ["enabled", "window_hours", "member_threshold"] - } - }, - "required": [ - "single_community_enabled", - "single_community_guild_id", - "direct_messages_disabled", - "direct_messages_locked", - "premium_mode", - "services", - "services_resolved", - "services_available", - "deferred_phone_gate" - ] - }, - "integrations": { - "type": "object", - "properties": { - "gif": { - "type": "object", - "properties": {"klipy_api_key_set": {"type": "boolean"}, "effective_available": {"type": "boolean"}}, - "required": ["klipy_api_key_set", "effective_available"] - }, - "youtube": { - "type": "object", - "properties": {"api_key_set": {"type": "boolean"}, "effective_available": {"type": "boolean"}}, - "required": ["api_key_set", "effective_available"] - }, - "captcha": { - "type": "object", - "properties": { - "provider": {"nullable": true, "enum": ["hcaptcha", "turnstile", "none"], "type": "string"}, - "effective_provider": {"enum": ["hcaptcha", "turnstile", "none"], "type": "string"}, - "hcaptcha_site_key": {"nullable": true, "type": "string"}, - "hcaptcha_secret_key_set": {"type": "boolean"}, - "turnstile_site_key": {"nullable": true, "type": "string"}, - "turnstile_secret_key_set": {"type": "boolean"}, - "effective_enabled": {"type": "boolean"} - }, - "required": [ - "provider", - "effective_provider", - "hcaptcha_site_key", - "hcaptcha_secret_key_set", - "turnstile_site_key", - "turnstile_secret_key_set", - "effective_enabled" - ] - }, - "email": { - "type": "object", - "properties": { - "enabled": {"nullable": true, "type": "boolean"}, - "effective_enabled": {"type": "boolean"}, - "provider": {"nullable": true, "enum": ["smtp", "none"], "type": "string"}, - "effective_provider": {"enum": ["smtp", "none"], "type": "string"}, - "from_email": {"nullable": true, "type": "string"}, - "from_name": {"nullable": true, "type": "string"}, - "smtp": { - "type": "object", - "properties": { - "host": {"nullable": true, "type": "string"}, - "port": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 65535, "format": "int32"}, - "username": {"nullable": true, "type": "string"}, - "password_set": {"type": "boolean"}, - "secure": {"nullable": true, "type": "boolean"} - }, - "required": ["host", "port", "username", "password_set", "secure"] - }, - "disable_new_ip_authorization": {"type": "boolean"}, - "effective_disable_new_ip_authorization": {"type": "boolean"} - }, - "required": [ - "enabled", - "effective_enabled", - "provider", - "effective_provider", - "from_email", - "from_name", - "smtp", - "disable_new_ip_authorization", - "effective_disable_new_ip_authorization" - ] - }, - "bluesky": { - "type": "object", - "properties": { - "enabled": {"nullable": true, "type": "boolean"}, - "effective_enabled": {"type": "boolean"}, - "client_name": {"nullable": true, "type": "string"}, - "client_uri": {"nullable": true, "type": "string"}, - "logo_uri": {"nullable": true, "type": "string"}, - "tos_uri": {"nullable": true, "type": "string"}, - "policy_uri": {"nullable": true, "type": "string"}, - "key_count": {"type": "integer", "minimum": 0, "maximum": 9007199254740991, "format": "int53"} - }, - "required": [ - "enabled", - "effective_enabled", - "client_name", - "client_uri", - "logo_uri", - "tos_uri", - "policy_uri", - "key_count" - ] - } - }, - "required": ["gif", "youtube", "captcha", "email", "bluesky"] - }, - "media": { - "type": "object", - "properties": { - "attachment_decay": { - "type": "object", - "properties": { - "enabled": {"nullable": true, "type": "boolean"}, - "min_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, - "max_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, - "max_eligible_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, - "min_lifetime_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "max_lifetime_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "curve": {"nullable": true, "type": "number", "minimum": 0, "maximum": 1}, - "renew_threshold_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "renew_window_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "effective": { - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "min_size_mb": {"type": "number", "minimum": 0, "exclusiveMinimum": true}, - "max_size_mb": {"type": "number", "minimum": 0, "exclusiveMinimum": true}, - "max_eligible_size_mb": {"type": "number", "minimum": 0, "exclusiveMinimum": true}, - "min_lifetime_days": { - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "max_lifetime_days": { - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "curve": {"type": "number", "minimum": 0, "maximum": 1}, - "renew_threshold_days": { - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "renew_window_days": { - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - } - }, - "required": [ - "enabled", - "min_size_mb", - "max_size_mb", - "max_eligible_size_mb", - "min_lifetime_days", - "max_lifetime_days", - "curve", - "renew_threshold_days", - "renew_window_days" - ] - } - }, - "required": [ - "enabled", - "min_size_mb", - "max_size_mb", - "max_eligible_size_mb", - "min_lifetime_days", - "max_lifetime_days", - "curve", - "renew_threshold_days", - "renew_window_days", - "effective" - ] - } - }, - "required": ["attachment_decay"] - } - }, - "required": [ - "sso", - "gateway_rollout", - "voice_noise_suppression", - "experiment_delivery", - "registration", - "self_hosted", - "app_public", - "policy", - "integrations", - "media" + "description": "Member profile flags", + "format": "int32", + "x-bitflagValues": [ + {"name": "AVATAR_UNSET", "value": "1", "description": "Guild member avatar is unset"}, + {"name": "BANNER_UNSET", "value": "2", "description": "Guild member banner is unset"} ] }, - "GatewayRolloutConfigSchema": { - "type": "object", - "properties": { - "session_rollout_percentage": {"type": "number", "minimum": 0, "maximum": 100}, - "session_rollout_mode": {"enum": ["modulo", "random"], "type": "string"}, - "guild_rollout_percentage": {"type": "number", "minimum": 0, "maximum": 100}, - "rpc_request_timeout_ms": {"type": "integer", "minimum": 1000, "maximum": 60000, "format": "int32"}, - "max_concurrent_session_starts": {"type": "integer", "minimum": 1, "maximum": 10000, "format": "int32"}, - "max_concurrent_guild_starts": {"type": "integer", "minimum": 1, "maximum": 10000, "format": "int32"}, - "gateway_dispatch_relay_shards": {"type": "integer", "minimum": 1, "maximum": 10000, "format": "int32"}, - "gateway_dispatch_relay_max_queue": {"type": "integer", "minimum": 0, "maximum": 1000000, "format": "int32"}, - "voice_e2ee_scope": {"enum": ["guild_feature_only", "platform_wide"], "type": "string"} - } + "InstanceCaptchaProviderSchema": {"type": "string", "enum": ["hcaptcha", "turnstile", "none"]}, + "InstanceRegistrationModeSchema": { + "description": "Registration mode", + "x-enumNames": ["open", "approval", "closed"], + "x-enumDescriptions": [ + "Anyone can register", + "Anyone can register, but admins must approve new accounts", + "Public registration is closed" + ], + "enum": ["open", "approval", "closed"], + "type": "string" }, - "VoiceNoiseSuppressionConfigSchema": { + "ExperimentDeliveryConfigUpdateRequest": { "type": "object", "properties": { - "enabled": {"type": "boolean"}, - "config_version": {"type": "integer", "minimum": 0, "maximum": 9007199254740991, "format": "int53"}, - "default_backend": { - "enum": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"], - "type": "string" - }, - "enabled_backends": { - "type": "array", - "items": { - "enum": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"], - "type": "string" - }, - "maxItems": 7 - }, - "allow_user_override": {"type": "boolean"}, - "rollout_basis_points": {"type": "integer", "minimum": 0, "maximum": 10000, "format": "int32"}, - "rollout_salt": {"type": "string", "minLength": 1, "maxLength": 64}, - "included_user_ids": { - "type": "array", - "items": {"type": "string", "pattern": "^\\d{1,20}$"}, - "maxItems": 1000 - }, - "excluded_user_ids": { - "type": "array", - "items": {"type": "string", "pattern": "^\\d{1,20}$"}, - "maxItems": 1000 - }, - "guild_overrides": { - "type": "array", - "items": { - "type": "object", - "properties": { - "guild_id": {"type": "string", "pattern": "^\\d{1,20}$"}, - "backend": { - "enum": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"], - "type": "string" - } - }, - "required": ["guild_id", "backend"] - }, - "maxItems": 200 - }, - "stereo_enabled": {"type": "boolean"}, - "suppression_strength": {"type": "integer", "minimum": 0, "maximum": 100, "format": "int32"} - } - }, - "ExperimentDeliveryConfigSchema": { - "type": "object", - "properties": { - "poll_interval_seconds": {"type": "integer", "minimum": 60, "maximum": 86400, "format": "int32"}, - "poll_jitter_percent": {"type": "integer", "minimum": 0, "maximum": 50, "format": "int32"} - } - }, - "InstanceConfigUpdateRequest": { - "type": "object", - "properties": { - "gateway_rollout": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/GatewayRolloutConfigUpdateRequest"}] - }, - "voice_noise_suppression": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/VoiceNoiseSuppressionConfigUpdateRequest"}] - }, - "experiment_delivery": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ExperimentDeliveryConfigUpdateRequest"}] - }, - "registration": { - "nullable": true, - "type": "object", - "properties": { - "mode": {"type": "string", "enum": ["open", "approval", "closed"], "description": "Registration mode"}, - "admin_registration_urls_enabled": {"type": "boolean"} - } - }, - "sso": { - "nullable": true, - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "enforced": {"type": "boolean"}, - "display_name": {"nullable": true, "type": "string"}, - "issuer": {"nullable": true, "type": "string"}, - "authorization_url": {"nullable": true, "type": "string"}, - "token_url": {"nullable": true, "type": "string"}, - "userinfo_url": {"nullable": true, "type": "string"}, - "jwks_url": {"nullable": true, "type": "string"}, - "client_id": {"nullable": true, "type": "string"}, - "client_secret": {"nullable": true, "type": "string"}, - "scope": {"nullable": true, "type": "string"}, - "allowed_domains": {"type": "array", "items": {"type": "string"}, "maxItems": 100}, - "auto_provision": {"type": "boolean"} - } - }, - "app_public": { - "nullable": true, - "type": "object", - "properties": { - "branding": { - "nullable": true, - "type": "object", - "properties": { - "product_name": {"type": "string", "minLength": 1, "maxLength": 80}, - "icon_url": {"nullable": true, "type": "string", "maxLength": 2048}, - "symbol_url": {"nullable": true, "type": "string", "maxLength": 2048}, - "logo_url": {"nullable": true, "type": "string", "maxLength": 2048}, - "wordmark_url": {"nullable": true, "type": "string", "maxLength": 2048}, - "favicon_url": {"nullable": true, "type": "string", "maxLength": 2048}, - "theme_color": {"nullable": true, "type": "string", "maxLength": 64} - } - }, - "setup": {"nullable": true, "type": "object", "properties": {"configured": {"type": "boolean"}}}, - "legal": { - "nullable": true, - "type": "object", - "properties": { - "terms_url": {"nullable": true, "type": "string", "maxLength": 2048}, - "privacy_url": {"nullable": true, "type": "string", "maxLength": 2048} - } - }, - "registration": { - "nullable": true, - "type": "object", - "properties": {"collect_date_of_birth": {"type": "boolean"}} - } - } - }, - "integrations": { - "nullable": true, - "type": "object", - "properties": { - "gif": { - "nullable": true, - "type": "object", - "properties": {"klipy_api_key": {"nullable": true, "type": "string", "maxLength": 4096}} - }, - "youtube": { - "nullable": true, - "type": "object", - "properties": {"api_key": {"nullable": true, "type": "string", "maxLength": 4096}} - }, - "captcha": { - "nullable": true, - "type": "object", - "properties": { - "provider": {"nullable": true, "enum": ["hcaptcha", "turnstile", "none"], "type": "string"}, - "hcaptcha_site_key": {"nullable": true, "type": "string", "maxLength": 4096}, - "hcaptcha_secret_key": {"nullable": true, "type": "string", "maxLength": 4096}, - "turnstile_site_key": {"nullable": true, "type": "string", "maxLength": 4096}, - "turnstile_secret_key": {"nullable": true, "type": "string", "maxLength": 4096} - } - }, - "email": { - "nullable": true, - "type": "object", - "properties": { - "enabled": {"nullable": true, "type": "boolean"}, - "provider": {"nullable": true, "enum": ["smtp", "none"], "type": "string"}, - "from_email": {"nullable": true, "type": "string", "maxLength": 320}, - "from_name": {"nullable": true, "type": "string", "maxLength": 120}, - "smtp": { - "nullable": true, - "type": "object", - "properties": { - "host": {"nullable": true, "type": "string", "maxLength": 255}, - "port": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 65535, "format": "int32"}, - "username": {"nullable": true, "type": "string", "maxLength": 320}, - "password": {"nullable": true, "type": "string", "maxLength": 4096}, - "secure": {"nullable": true, "type": "boolean"} - } - }, - "disable_new_ip_authorization": {"nullable": true, "type": "boolean"} - } - }, - "bluesky": { - "nullable": true, - "type": "object", - "properties": { - "enabled": {"nullable": true, "type": "boolean"}, - "client_name": {"nullable": true, "type": "string", "maxLength": 120}, - "client_uri": {"nullable": true, "type": "string", "maxLength": 2048}, - "logo_uri": {"nullable": true, "type": "string", "maxLength": 2048}, - "tos_uri": {"nullable": true, "type": "string", "maxLength": 2048}, - "policy_uri": {"nullable": true, "type": "string", "maxLength": 2048}, - "keys": { - "type": "array", - "items": { - "type": "object", - "properties": { - "kid": {"type": "string", "minLength": 1, "maxLength": 255}, - "private_key": {"nullable": true, "type": "string", "maxLength": 10000} - }, - "required": ["kid"] - }, - "maxItems": 8 - } - } - } - } - }, - "media": { - "nullable": true, - "type": "object", - "properties": { - "attachment_decay": { - "nullable": true, - "type": "object", - "properties": { - "enabled": {"nullable": true, "type": "boolean"}, - "min_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, - "max_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, - "max_eligible_size_mb": {"nullable": true, "type": "number", "minimum": 0, "exclusiveMinimum": true}, - "min_lifetime_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "max_lifetime_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "curve": {"nullable": true, "type": "number", "minimum": 0, "maximum": 1}, - "renew_threshold_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - }, - "renew_window_days": { - "nullable": true, - "type": "integer", - "maximum": 9007199254740991, - "format": "int53", - "minimum": 0, - "exclusiveMinimum": true - } - } - } - } - }, - "policy": { - "nullable": true, - "type": "object", - "properties": { - "single_community_enabled": {"type": "boolean"}, - "single_community_name": {"type": "string", "minLength": 1, "maxLength": 100}, - "direct_messages_disabled": {"type": "boolean"}, - "direct_messages_locked": {"type": "boolean", "enum": [false]}, - "premium_mode": {"enum": ["mirror", "everyone"], "type": "string"}, - "services": { - "nullable": true, - "type": "object", - "properties": { - "gif_enabled": {"nullable": true, "type": "boolean"}, - "youtube_enabled": {"nullable": true, "type": "boolean"}, - "bluesky_enabled": {"nullable": true, "type": "boolean"} - } - }, - "deferred_phone_gate": { - "nullable": true, - "type": "object", - "properties": { - "enabled": {"type": "boolean"}, - "window_hours": {"type": "number", "maximum": 8760, "minimum": 0, "exclusiveMinimum": true}, - "member_threshold": { - "type": "integer", - "maximum": 1000000, - "format": "int32", - "minimum": 0, - "exclusiveMinimum": true - } - } - } - } - } - } - }, - "GatewayRolloutConfigUpdateRequest": { - "type": "object", - "properties": { - "session_rollout_percentage": {"type": "number", "minimum": 0, "maximum": 100}, - "session_rollout_mode": {"enum": ["modulo", "random"], "type": "string"}, - "guild_rollout_percentage": {"type": "number", "minimum": 0, "maximum": 100}, - "rpc_request_timeout_ms": {"type": "integer", "minimum": 1000, "maximum": 60000, "format": "int32"}, - "max_concurrent_session_starts": {"type": "integer", "minimum": 1, "maximum": 10000, "format": "int32"}, - "max_concurrent_guild_starts": {"type": "integer", "minimum": 1, "maximum": 10000, "format": "int32"}, - "gateway_dispatch_relay_shards": {"type": "integer", "minimum": 1, "maximum": 10000, "format": "int32"}, - "gateway_dispatch_relay_max_queue": {"type": "integer", "minimum": 0, "maximum": 1000000, "format": "int32"}, - "voice_e2ee_scope": {"enum": ["guild_feature_only", "platform_wide"], "type": "string"} + "poll_interval_seconds": {"type": "integer", "minimum": 60, "maximum": 86400}, + "poll_jitter_percent": {"type": "integer", "minimum": 0, "maximum": 50} } }, "VoiceNoiseSuppressionConfigUpdateRequest": { "type": "object", "properties": { "enabled": {"type": "boolean"}, - "default_backend": { - "enum": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"], - "type": "string" - }, + "default_backend": {"allOf": [{"$ref": "#/components/schemas/VoiceNoiseSuppressionBackendSchema"}]}, "enabled_backends": { + "maxItems": 7, "type": "array", - "items": { - "enum": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"], - "type": "string" - }, - "maxItems": 7 + "items": {"$ref": "#/components/schemas/VoiceNoiseSuppressionBackendSchema"} }, "allow_user_override": {"type": "boolean"}, - "rollout_basis_points": {"type": "integer", "minimum": 0, "maximum": 10000, "format": "int32"}, + "rollout_basis_points": {"type": "integer", "minimum": 0, "maximum": 10000}, "rollout_salt": {"type": "string", "minLength": 1, "maxLength": 64}, "included_user_ids": { + "maxItems": 1000, "type": "array", - "items": {"type": "string", "pattern": "^\\d{1,20}$"}, - "maxItems": 1000 + "items": {"type": "string", "pattern": "^\\d{1,20}$"} }, "excluded_user_ids": { + "maxItems": 1000, "type": "array", - "items": {"type": "string", "pattern": "^\\d{1,20}$"}, - "maxItems": 1000 + "items": {"type": "string", "pattern": "^\\d{1,20}$"} }, "guild_overrides": { + "maxItems": 200, "type": "array", "items": { "type": "object", "properties": { "guild_id": {"type": "string", "pattern": "^\\d{1,20}$"}, - "backend": { - "enum": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"], - "type": "string" - } + "backend": {"$ref": "#/components/schemas/VoiceNoiseSuppressionBackendSchema"} }, "required": ["guild_id", "backend"] - }, - "maxItems": 200 + } }, "stereo_enabled": {"type": "boolean"}, - "suppression_strength": {"type": "integer", "minimum": 0, "maximum": 100, "format": "int32"} + "suppression_strength": {"type": "integer", "minimum": 0, "maximum": 100} } }, - "ExperimentDeliveryConfigUpdateRequest": { + "GatewayRolloutConfigUpdateRequest": { "type": "object", "properties": { - "poll_interval_seconds": {"type": "integer", "minimum": 60, "maximum": 86400, "format": "int32"}, - "poll_jitter_percent": {"type": "integer", "minimum": 0, "maximum": 50, "format": "int32"} + "session_rollout_percentage": {"type": "number", "minimum": 0, "maximum": 100}, + "session_rollout_mode": {"type": "string", "enum": ["modulo", "random"]}, + "guild_rollout_percentage": {"type": "number", "minimum": 0, "maximum": 100}, + "rpc_request_timeout_ms": {"type": "integer", "minimum": 1000, "maximum": 60000}, + "max_concurrent_session_starts": {"type": "integer", "minimum": 1, "maximum": 10000}, + "max_concurrent_guild_starts": {"type": "integer", "minimum": 1, "maximum": 10000}, + "gateway_dispatch_relay_shards": {"type": "integer", "minimum": 1, "maximum": 10000}, + "gateway_dispatch_relay_max_queue": {"type": "integer", "minimum": 0, "maximum": 1000000}, + "voice_e2ee_scope": {"type": "string", "enum": ["guild_feature_only", "platform_wide"]} } }, - "BrandingAssetUploadRequest": { + "VoiceNoiseSuppressionBackendSchema": { + "type": "string", + "enum": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"] + }, + "ExperimentDeliveryConfigResponse": { "type": "object", "properties": { - "kind": {"enum": ["icon", "symbol", "logo", "wordmark", "favicon"], "type": "string"}, - "image": {"nullable": true, "type": "string", "maxLength": 16000000} + "poll_interval_seconds": {"default": 300, "type": "integer", "minimum": 60, "maximum": 86400}, + "poll_jitter_percent": {"default": 15, "type": "integer", "minimum": 0, "maximum": 50} }, - "required": ["kind"] + "required": ["poll_interval_seconds", "poll_jitter_percent"], + "additionalProperties": false }, - "InstanceEmailSmtpTestResponse": { - "type": "object", - "properties": {"ok": {"type": "boolean"}, "error": {"nullable": true, "type": "string"}}, - "required": ["ok", "error"] - }, - "InstanceEmailSmtpTestRequest": { + "VoiceNoiseSuppressionConfigResponse": { "type": "object", "properties": { - "host": {"type": "string", "minLength": 1, "maxLength": 255}, - "port": {"type": "integer", "minimum": 1, "maximum": 65535, "format": "int32"}, - "username": {"type": "string", "minLength": 1, "maxLength": 320}, - "password": {"type": "string", "minLength": 1, "maxLength": 4096}, - "secure": {"type": "boolean"} - }, - "required": ["host", "port", "username", "password"] - }, - "PendingRegistrationActionRequest": { - "type": "object", - "properties": { - "status": {"type": "string", "enum": ["approved", "rejected"], "description": "Pending registration decision"} - }, - "required": ["status"] - }, - "CreateRegistrationUrlResponse": { - "type": "object", - "properties": { - "registration_url": { - "type": "object", - "properties": { - "id": {"type": "string"}, - "label": {"nullable": true, "type": "string"}, - "created_by_user_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "created_at": {"type": "string", "format": "date-time"}, - "expires_at": {"nullable": true, "type": "string", "format": "date-time"}, - "max_uses": { - "nullable": true, - "type": "integer", - "minimum": 1, - "maximum": 9007199254740991, - "format": "int53" - }, - "use_count": {"type": "integer", "minimum": 0, "maximum": 9007199254740991, "format": "int53"}, - "revoked_at": {"nullable": true, "type": "string", "format": "date-time"}, - "approval_required": {"type": "boolean"}, - "last_used_at": {"nullable": true, "type": "string", "format": "date-time"}, - "last_used_by_user_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]} - }, - "required": [ - "id", - "label", - "created_by_user_id", - "created_at", - "expires_at", - "max_uses", - "use_count", - "revoked_at", - "approval_required", - "last_used_at", - "last_used_by_user_id" - ] + "enabled": {"default": false, "type": "boolean"}, + "config_version": {"default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991}, + "default_backend": { + "default": "standard", + "allOf": [{"$ref": "#/components/schemas/VoiceNoiseSuppressionBackendSchema"}] }, - "code": {"type": "string"}, - "url": {"type": "string"} + "enabled_backends": { + "default": ["none", "standard", "gate", "speex", "rnnoise", "gtcrn", "deep_filter"], + "maxItems": 7, + "type": "array", + "items": {"$ref": "#/components/schemas/VoiceNoiseSuppressionBackendSchema"} + }, + "allow_user_override": {"default": true, "type": "boolean"}, + "rollout_basis_points": {"default": 0, "type": "integer", "minimum": 0, "maximum": 10000}, + "rollout_salt": {"default": "voice-ns-v1", "type": "string", "minLength": 1, "maxLength": 64}, + "included_user_ids": { + "default": [], + "maxItems": 1000, + "type": "array", + "items": {"type": "string", "pattern": "^\\d{1,20}$"} + }, + "excluded_user_ids": { + "default": [], + "maxItems": 1000, + "type": "array", + "items": {"type": "string", "pattern": "^\\d{1,20}$"} + }, + "guild_overrides": { + "default": [], + "maxItems": 200, + "type": "array", + "items": { + "type": "object", + "properties": { + "guild_id": {"type": "string", "pattern": "^\\d{1,20}$"}, + "backend": {"$ref": "#/components/schemas/VoiceNoiseSuppressionBackendSchema"} + }, + "required": ["guild_id", "backend"], + "additionalProperties": false + } + }, + "stereo_enabled": {"default": false, "type": "boolean"}, + "suppression_strength": {"default": 80, "type": "integer", "minimum": 0, "maximum": 100} }, - "required": ["registration_url", "code", "url"] + "required": [ + "enabled", + "config_version", + "default_backend", + "enabled_backends", + "allow_user_override", + "rollout_basis_points", + "rollout_salt", + "included_user_ids", + "excluded_user_ids", + "guild_overrides", + "stereo_enabled", + "suppression_strength" + ], + "additionalProperties": false }, - "CreateRegistrationUrlRequest": { + "GatewayRolloutConfigResponse": { "type": "object", "properties": { - "label": {"nullable": true, "type": "string", "minLength": 1, "maxLength": 120}, - "expires_at": {"nullable": true, "type": "string", "format": "date-time"}, - "max_uses": {"nullable": true, "type": "integer", "minimum": 1, "maximum": 1000000, "format": "int32"}, - "approval_required": {"type": "boolean"} - } - }, - "ListJobsResponseSchema": { - "type": "object", - "properties": { - "jobs": {"type": "array", "items": {"$ref": "#/components/schemas/JobLedgerEntrySchema"}}, - "next_cursor": { - "nullable": true, - "type": "object", - "properties": { - "bucket_day": {"type": "string"}, - "created_at": {"type": "string"}, - "job_id": {"$ref": "#/components/schemas/SnowflakeType"} - }, - "required": ["bucket_day", "created_at", "job_id"] + "session_rollout_percentage": {"default": 100, "type": "number", "minimum": 0, "maximum": 100}, + "session_rollout_mode": {"default": "modulo", "type": "string", "enum": ["modulo", "random"]}, + "guild_rollout_percentage": {"default": 100, "type": "number", "minimum": 0, "maximum": 100}, + "rpc_request_timeout_ms": {"default": 10000, "type": "integer", "minimum": 1000, "maximum": 60000}, + "max_concurrent_session_starts": {"default": 512, "type": "integer", "minimum": 1, "maximum": 10000}, + "max_concurrent_guild_starts": {"default": 256, "type": "integer", "minimum": 1, "maximum": 10000}, + "gateway_dispatch_relay_shards": {"default": 32, "type": "integer", "minimum": 1, "maximum": 10000}, + "gateway_dispatch_relay_max_queue": {"default": 50000, "type": "integer", "minimum": 0, "maximum": 1000000}, + "voice_e2ee_scope": { + "default": "guild_feature_only", + "type": "string", + "enum": ["guild_feature_only", "platform_wide"] } }, - "required": ["jobs", "next_cursor"] + "required": [ + "session_rollout_percentage", + "session_rollout_mode", + "guild_rollout_percentage", + "rpc_request_timeout_ms", + "max_concurrent_session_starts", + "max_concurrent_guild_starts", + "gateway_dispatch_relay_shards", + "gateway_dispatch_relay_max_queue", + "voice_e2ee_scope" + ], + "additionalProperties": false }, "JobLedgerEntrySchema": { "type": "object", "properties": { - "job_id": {"$ref": "#/components/schemas/SnowflakeType"}, + "job_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, "task_type": {"type": "string"}, - "status": {"enum": ["queued", "running", "succeeded", "cancelled", "deadletter"], "type": "string"}, + "status": {"type": "string", "enum": ["queued", "running", "succeeded", "cancelled", "deadletter"]}, "progress_current": {"nullable": true, "type": "number"}, "progress_total": {"nullable": true, "type": "number"}, "progress_message": {"nullable": true, "type": "string"}, @@ -12766,17 +15302,17 @@ "created_at": {"type": "string", "description": "ISO 8601"}, "started_at": {"nullable": true, "type": "string"}, "completed_at": {"nullable": true, "type": "string"}, - "requested_by_user_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, + "requested_by_user_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeStringType"}]}, "audit_log_reason": {"nullable": true, "type": "string"}, "jet_stream_lane": {"nullable": true, "type": "string"}, "jet_stream_seq": {"nullable": true, "type": "string"}, - "attempts": {"type": "integer", "format": "int53"}, - "max_attempts": {"type": "integer", "format": "int53"}, + "attempts": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991}, + "max_attempts": {"type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991}, "run_at": {"nullable": true, "type": "string"}, "cancel_requested": {"type": "boolean"}, "context_link": {"nullable": true, "type": "string"}, - "payload": {"description": "JSON-encoded original payload", "nullable": true, "type": "string"}, - "result": {"description": "JSON-encoded result, if any", "nullable": true, "type": "string"} + "payload": {"nullable": true, "description": "JSON-encoded original payload", "type": "string"}, + "result": {"nullable": true, "description": "JSON-encoded result, if any", "type": "string"} }, "required": [ "job_id", @@ -12800,547 +15336,36 @@ "context_link", "payload", "result" - ] + ], + "additionalProperties": false }, - "ActiveJobsResponseSchema": { - "type": "object", - "properties": {"jobs": {"type": "array", "items": {"$ref": "#/components/schemas/JobLedgerEntrySchema"}}}, - "required": ["jobs"] - }, - "GetJobResponseSchema": { - "type": "object", - "properties": {"job": {"$ref": "#/components/schemas/JobLedgerEntrySchema"}}, - "required": ["job"] - }, - "CancelJobResponseSchema": { - "type": "object", - "properties": { - "cancelled": { - "type": "boolean", - "description": "True if a cancel request was recorded; false if the job was already terminal." - } - }, - "required": ["cancelled"] - }, - "LimitConfigGetResponse": { - "type": "object", - "properties": { - "limit_config": { - "type": "object", - "properties": { - "traitDefinitions": {"type": "array", "items": {"type": "string"}}, - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"type": "string", "minLength": 1, "description": "Unique rule identifier"}, - "filters": { - "type": "object", - "properties": { - "traits": { - "type": "array", - "items": {"type": "string"}, - "description": "Trait filters that must match for the rule to apply" - }, - "guildFeatures": { - "type": "array", - "items": {"type": "string"}, - "description": "Guild feature flags required for the rule to apply" - } - }, - "description": "Optional filters that scope the rule" - }, - "limits": { - "type": "object", - "additionalProperties": {"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}, - "description": "Per-limit key values" - }, - "modifiedFields": {"type": "array", "items": {"type": "string"}} - }, - "required": ["id", "limits"] - } - } - }, - "required": ["traitDefinitions", "rules"] - }, - "limit_config_json": {"type": "string"}, - "self_hosted": {"type": "boolean"}, - "defaults": { - "type": "object", - "additionalProperties": {"type": "object", "additionalProperties": {"type": "number"}} - }, - "metadata": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "key": {"type": "string"}, - "label": {"type": "string"}, - "description": {"type": "string"}, - "category": {"type": "string"}, - "scope": {"type": "string"}, - "isToggle": {"type": "boolean"}, - "unit": {"enum": ["bytes", "count"], "type": "string"}, - "min": {"type": "number"}, - "max": {"type": "number"} - }, - "required": ["key", "label", "description", "category", "scope", "isToggle"] - } - }, - "categories": {"type": "object", "additionalProperties": {"type": "string"}}, - "limit_keys": {"type": "array", "items": {"type": "string"}}, - "bounds": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {"min": {"type": "number"}, "max": {"type": "number"}}, - "required": ["min", "max"] - } - } - }, - "required": [ - "limit_config", - "limit_config_json", - "self_hosted", - "defaults", - "metadata", - "categories", - "limit_keys" - ] - }, - "LimitConfigUpdateRequest": { - "type": "object", - "properties": { - "limit_config": { - "type": "object", - "properties": { - "traitDefinitions": { - "type": "array", - "items": {"type": "string"}, - "description": "Trait definitions used by rules" - }, - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"type": "string", "minLength": 1, "description": "Unique rule identifier"}, - "filters": { - "type": "object", - "properties": { - "traits": { - "type": "array", - "items": {"type": "string"}, - "description": "Trait filters that must match for the rule to apply" - }, - "guildFeatures": { - "type": "array", - "items": {"type": "string"}, - "description": "Guild feature flags required for the rule to apply" - } - }, - "description": "Optional filters that scope the rule" - }, - "limits": { - "type": "object", - "additionalProperties": {"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}, - "description": "Per-limit key values" - } - }, - "required": ["id", "limits"] - }, - "description": "Limit rules" - } - }, - "required": ["rules"], - "description": "New limit configuration snapshot" - } - }, - "required": ["limit_config"] - }, - "AdminMessageSearchResponse": { - "oneOf": [ - { - "type": "object", - "properties": { - "messages": { - "type": "array", - "items": {"$ref": "#/components/schemas/AdminMessageSchema"}, - "maxItems": 100 - }, - "message_responses": { - "type": "array", - "items": {"$ref": "#/components/schemas/MessageResponseSchema"}, - "maxItems": 100 - }, - "total": {"type": "integer", "minimum": 0, "maximum": 9007199254740991, "format": "int53"} - }, - "required": ["messages", "total"] - }, - {"$ref": "#/components/schemas/LookupMessageResponse"} - ] - }, - "NcmecAttachmentSubmitResultResponse": { - "type": "object", - "properties": { - "success": {"type": "boolean", "enum": [true]}, - "ncmec_report_id": {"type": "string"}, - "audit_log_reason": {"type": "string"} - }, - "required": ["success", "ncmec_report_id", "audit_log_reason"] - }, - "ReportAttachmentToNcmecRequest": { - "type": "object", - "properties": { - "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "message_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "attachment_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "filename": {"type": "string"}, - "source_report_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "reporter_full_name": {"type": "string", "minLength": 1, "maxLength": 200}, - "confirmed_viewed": {"type": "boolean", "enum": [true]} - }, - "required": ["channel_id", "message_id", "attachment_id", "filename", "reporter_full_name", "confirmed_viewed"] - }, - "MessageShredStatusResponse": { - "oneOf": [ - { - "type": "object", - "properties": {"status": {"type": "string", "enum": ["not_found"]}}, - "required": ["status"] - }, - { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": ["in_progress", "completed", "failed"], - "description": "Current message shred job status" - }, - "requested": {"$ref": "#/components/schemas/Int32Type"}, - "total": {"$ref": "#/components/schemas/Int32Type"}, - "processed": {"$ref": "#/components/schemas/Int32Type"}, - "skipped": {"$ref": "#/components/schemas/Int32Type"}, - "started_at": {"type": "string"}, - "completed_at": {"type": "string"}, - "failed_at": {"type": "string"}, - "error": {"type": "string"} - }, - "required": ["status", "requested", "total", "processed", "skipped"] - } - ] - }, - "AdminReportListResponse": { - "type": "object", - "properties": { - "reports": {"type": "array", "items": {"$ref": "#/components/schemas/ReportAdminResponseSchema"}}, - "total": {"type": "number"}, - "offset": {"type": "number"}, - "limit": {"type": "number"} - }, - "required": ["reports", "total", "offset", "limit"] - }, - "ReportAdminResponseSchema": { - "type": "object", - "properties": { - "report_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "reporter_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "reporter_tag": {"nullable": true, "type": "string"}, - "reporter_username": {"nullable": true, "type": "string"}, - "reporter_global_name": {"nullable": true, "type": "string"}, - "reporter_discriminator": {"nullable": true, "type": "string"}, - "reporter_email": {"nullable": true, "type": "string"}, - "reporter_full_legal_name": {"nullable": true, "type": "string"}, - "reporter_country_of_residence": {"nullable": true, "type": "string"}, - "reported_at": {"type": "string"}, - "status": {"$ref": "#/components/schemas/ReportStatus"}, - "report_type": {"$ref": "#/components/schemas/ReportType"}, - "category": {"nullable": true, "type": "string"}, - "additional_info": {"nullable": true, "type": "string"}, - "reported_user_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "reported_user_tag": {"nullable": true, "type": "string"}, - "reported_user_username": {"nullable": true, "type": "string"}, - "reported_user_global_name": {"nullable": true, "type": "string"}, - "reported_user_discriminator": {"nullable": true, "type": "string"}, - "reported_user_avatar_hash": {"nullable": true, "type": "string"}, - "reported_guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "reported_guild_name": {"nullable": true, "type": "string"}, - "reported_guild_icon_hash": {"nullable": true, "type": "string"}, - "reported_message_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "reported_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "reported_channel_name": {"nullable": true, "type": "string"}, - "reported_channel_nsfw": {"nullable": true, "type": "boolean"}, - "reported_guild_invite_code": {"nullable": true, "type": "string"}, - "reported_guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, - "reported_guild_nsfw": {"nullable": true, "type": "boolean"}, - "reported_guild_content_warning_level": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] - }, - "reported_guild_content_warning_text": {"nullable": true, "type": "string"}, - "reported_channel_nsfw_override": {"nullable": true, "type": "boolean"}, - "reported_channel_content_warning_level": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] - }, - "reported_channel_content_warning_text": {"nullable": true, "type": "string"}, - "reported_channel_effective_nsfw": {"nullable": true, "type": "boolean"}, - "reported_channel_effective_content_warning_level": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] - }, - "reported_channel_effective_content_warning_text": {"nullable": true, "type": "string"}, - "resolved_at": {"nullable": true, "type": "string"}, - "resolved_by_admin_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "public_comment": {"nullable": true, "type": "string"}, - "mutual_dm_channel_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "message_context": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "channel_nsfw": {"nullable": true, "type": "boolean"}, - "channel_content_warning_level": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] - }, - "channel_content_warning_text": {"nullable": true, "type": "string"}, - "guild_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, - "guild_nsfw": {"nullable": true, "type": "boolean"}, - "guild_content_warning_level": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/ContentWarningLevel"}] - }, - "guild_content_warning_text": {"nullable": true, "type": "string"}, - "content": {"type": "string"}, - "timestamp": {"type": "string"}, - "attachments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "filename": {"type": "string"}, - "url": {"type": "string"}, - "nsfw": {"nullable": true, "type": "boolean"}, - "content_type": {"nullable": true, "type": "string"}, - "width": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, - "height": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, - "size": { - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/NonNegativeSafeIntegerType"}] - }, - "ncmec_status": { - "type": "string", - "enum": ["not_submitted", "submitted", "failed"], - "description": "NCMEC submission status" - }, - "ncmec_report_id": {"nullable": true, "type": "string"}, - "ncmec_failure_reason": {"nullable": true, "type": "string"} - }, - "required": [ - "id", - "filename", - "url", - "nsfw", - "content_type", - "width", - "height", - "ncmec_status", - "ncmec_report_id", - "ncmec_failure_reason" - ] - } - }, - "author_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "author_username": {"type": "string"}, - "author_global_name": {"nullable": true, "type": "string"}, - "author_discriminator": {"type": "string"}, - "author_avatar": {"nullable": true, "type": "string"}, - "user_prior_ncmec_report_ids": {"type": "array", "items": {"type": "string"}, "maxItems": 100} - }, - "required": [ - "id", - "channel_id", - "channel_nsfw", - "guild_id", - "guild_nsfw_level", - "content", - "timestamp", - "attachments", - "author_id", - "author_username", - "author_global_name", - "author_discriminator", - "author_avatar" - ] - } - }, - "message_responses": {"type": "array", "items": {"$ref": "#/components/schemas/MessageResponseSchema"}} - }, - "required": [ - "report_id", - "reporter_id", - "reporter_tag", - "reporter_username", - "reporter_global_name", - "reporter_discriminator", - "reporter_email", - "reporter_full_legal_name", - "reporter_country_of_residence", - "reported_at", - "status", - "report_type", - "category", - "additional_info", - "reported_user_id", - "reported_user_tag", - "reported_user_username", - "reported_user_global_name", - "reported_user_discriminator", - "reported_user_avatar_hash", - "reported_guild_id", - "reported_guild_name", - "reported_guild_icon_hash", - "reported_message_id", - "reported_channel_id", - "reported_channel_name", - "reported_channel_nsfw", - "reported_guild_invite_code", - "reported_guild_nsfw_level", - "resolved_at", - "resolved_by_admin_id", - "public_comment" - ] - }, - "ReportStatus": {"type": "integer", "format": "int32", "enum": [0, 1], "description": "The status of the report"}, "ReportType": { + "description": "The type of entity being reported", "type": "integer", - "format": "int32", "enum": [0, 1, 2], - "description": "The type of entity being reported" + "format": "int32", + "x-enumNames": ["MESSAGE", "USER", "GUILD"], + "x-enumDescriptions": ["Report of a message", "Report of a user", "Report of a guild"] }, - "ResolveReportResponse": { - "type": "object", - "properties": { - "report_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "status": {"$ref": "#/components/schemas/ReportStatus"}, - "resolved_at": {"nullable": true, "type": "string"}, - "public_comment": {"nullable": true, "type": "string"} - }, - "required": ["report_id", "status", "resolved_at", "public_comment"] - }, - "UpdateReportRequest": { - "type": "object", - "properties": { - "status": {"type": "string", "enum": ["resolved"], "description": "The status to move the report to"}, - "public_comment": {"type": "string", "description": "Public comment to include with the resolution"} - }, - "required": ["status"] - }, - "IndexRefreshStatusResponse": { - "oneOf": [ - { - "type": "object", - "properties": {"status": {"type": "string", "enum": ["not_found"], "description": "Job was not found"}}, - "required": ["status"] - }, - { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": ["in_progress", "completed", "failed"], - "description": "Current status of the index refresh job" - }, - "index_type": {"type": "string", "description": "Type of index being refreshed"}, - "total": {"type": "number", "description": "Total number of items to index"}, - "indexed": {"type": "number", "description": "Number of items indexed so far"}, - "started_at": {"type": "string", "description": "ISO 8601 timestamp when the job started"}, - "completed_at": {"type": "string", "description": "ISO 8601 timestamp when the job completed"}, - "failed_at": {"type": "string", "description": "ISO 8601 timestamp when the job failed"}, - "error": {"type": "string", "description": "Error message if the job failed"} - }, - "required": ["status", "index_type"] - } - ] - }, - "RefreshSearchIndexResponse": { - "type": "object", - "properties": {"success": {"type": "boolean", "enum": [true]}, "job_id": {"type": "string"}}, - "required": ["success", "job_id"] - }, - "RefreshSearchIndexRequest": { - "type": "object", - "properties": { - "guild_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "user_id": {"$ref": "#/components/schemas/SnowflakeType"} - } - }, - "SendSystemDmResponse": { - "type": "object", - "properties": { - "recipient_count": { - "type": "integer", - "minimum": 0, - "maximum": 2147483647, - "format": "int32", - "description": "Number of recipients the worker job was queued to deliver to" - } - }, - "required": ["recipient_count"] - }, - "SendSystemDmRequest": { - "type": "object", - "properties": { - "content": { - "type": "string", - "minLength": 1, - "maxLength": 4000, - "description": "Message content to send to each recipient" - }, - "user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "minItems": 1, - "maxItems": 10000, - "description": "Recipient user IDs. Each receives the same content as a system DM." - } - }, - "required": ["content", "user_ids"] - }, - "HeapSnapshotResponse": { - "type": "object", - "properties": { - "success": {"type": "boolean", "enum": [true]}, - "filename": {"type": "string", "description": "Name of the heap snapshot file"}, - "size_bytes": {"type": "number", "description": "Size of the heap snapshot in bytes"} - }, - "required": ["success", "filename", "size_bytes"] - }, - "SearchUsersResponse": { - "type": "object", - "properties": { - "users": {"type": "array", "items": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}, - "total": {"type": "number"} - }, - "required": ["users", "total"] + "ReportStatus": { + "description": "The status of the report", + "type": "integer", + "enum": [0, 1], + "format": "int32", + "x-enumNames": ["PENDING", "RESOLVED"], + "x-enumDescriptions": ["Report is pending review", "Report has been resolved"] }, "UserAdminResponseSchema": { "type": "object", "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, "username": {"type": "string"}, "discriminator": {"$ref": "#/components/schemas/Int32Type"}, "global_name": {"nullable": true, "type": "string"}, "bot": {"type": "boolean"}, "system": {"type": "boolean"}, - "flags": {"$ref": "#/components/schemas/UserFlags"}, - "premium_flags": {"$ref": "#/components/schemas/PremiumFlags"}, + "flags": {"allOf": [{"$ref": "#/components/schemas/UserFlags"}]}, + "premium_flags": {"allOf": [{"$ref": "#/components/schemas/PremiumFlags"}]}, "avatar": {"nullable": true, "type": "string"}, "banner": {"nullable": true, "type": "string"}, "bio": {"nullable": true, "type": "string"}, @@ -13357,7 +15382,7 @@ "premium_until": {"nullable": true, "type": "string"}, "premium_grace_ends_at": {"nullable": true, "type": "string"}, "premium_lifetime_sequence": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, - "suspicious_activity_flags": {"$ref": "#/components/schemas/SuspiciousActivityFlags"}, + "suspicious_activity_flags": {"allOf": [{"$ref": "#/components/schemas/SuspiciousActivityFlags"}]}, "phone_verification_deferred": { "type": "boolean", "description": "Whether a stored phone requirement is deferred until the user joins a discoverable or large community" @@ -13367,10 +15392,10 @@ "pending_bulk_message_deletion_at": {"nullable": true, "type": "string"}, "deletion_reason_code": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, "deletion_public_reason": {"nullable": true, "type": "string"}, - "acls": {"type": "array", "items": {"type": "string"}, "maxItems": 112}, - "traits": {"type": "array", "items": {"type": "string"}, "maxItems": 100}, + "acls": {"maxItems": 112, "type": "array", "items": {"type": "string"}}, + "traits": {"maxItems": 100, "type": "array", "items": {"type": "string"}}, "has_totp": {"type": "boolean"}, - "authenticator_types": {"type": "array", "items": {"$ref": "#/components/schemas/Int32Type"}, "maxItems": 10}, + "authenticator_types": {"maxItems": 10, "type": "array", "items": {"$ref": "#/components/schemas/Int32Type"}}, "last_active_at": {"nullable": true, "type": "string"}, "last_active_ip": {"nullable": true, "type": "string"}, "last_active_ip_reverse": {"nullable": true, "type": "string"}, @@ -13416,376 +15441,77 @@ "last_active_ip", "last_active_ip_reverse", "last_active_location" + ], + "additionalProperties": false + }, + "SuspiciousActivityFlags": { + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "description": "Suspicious activity indicators", + "format": "int32", + "x-bitflagValues": [ + {"name": "REQUIRE_VERIFIED_EMAIL", "value": "1", "description": "Requires verified email address"}, + {"name": "REQUIRE_REVERIFIED_EMAIL", "value": "2", "description": "Requires re-verified email address"}, + {"name": "REQUIRE_VERIFIED_PHONE", "value": "4", "description": "Requires verified phone number"}, + {"name": "REQUIRE_REVERIFIED_PHONE", "value": "8", "description": "Requires re-verified phone number"}, + { + "name": "REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE", + "value": "16", + "description": "Requires verified email or verified phone" + }, + { + "name": "REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE", + "value": "32", + "description": "Requires re-verified email or re-verified phone" + }, + { + "name": "REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE", + "value": "64", + "description": "Requires verified email or re-verified phone" + }, + { + "name": "REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE", + "value": "128", + "description": "Requires re-verified email or re-verified phone" + }, + { + "name": "REQUIRE_INBOUND_PHONE_VERIFICATION", + "value": "256", + "description": "Requires inbound SMS verification (user must text code to platform number)" + } ] }, "PremiumFlags": { "type": "integer", - "format": "int32", "minimum": 0, "maximum": 2147483647, - "description": "A single premium flag value to add or remove" - }, - "SuspiciousActivityFlags": { - "type": "integer", + "description": "User premium-related flags (32-bit)", "format": "int32", - "minimum": 0, - "maximum": 2147483647, - "description": "Bitmask of suspicious activity flags" - }, - "AdminUsersMeResponse": { - "type": "object", - "properties": {"user": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}, - "required": ["user"] - }, - "LookupUserResponse": { - "type": "object", - "properties": {"users": {"type": "array", "items": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}}, - "required": ["users"] - }, - "UserMutationResponse": { - "type": "object", - "properties": {"user": {"$ref": "#/components/schemas/UserAdminResponseSchema"}}, - "required": ["user"] - }, - "AdminUserAclsRequest": { - "type": "object", - "properties": { - "acls": { - "type": "array", - "items": {"$ref": "#/components/schemas/AdminAclType"}, - "maxItems": 112, - "description": "List of access control permissions to assign" - } - }, - "required": ["acls"] - }, - "BanUserAvatarResponseSchema": { - "type": "object", - "properties": {"hash_short": {"type": "string"}}, - "required": ["hash_short"] - }, - "BanUserAvatarRequest": { - "type": "object", - "properties": {"reason": {"type": "string"}, "notes": {"type": "string"}} - }, - "AdminUserBanRequest": { - "type": "object", - "properties": { - "duration_hours": { - "type": "integer", - "minimum": 0, - "maximum": 8760, - "format": "int32", - "description": "Duration of the ban in hours. Use 0 for a permanent ban (until manually unbanned)." - }, - "reason": {"type": "string", "description": "Reason for the temporary ban"} - }, - "required": ["duration_hours"] - }, - "AdminUserBotStatusRequest": { - "type": "object", - "properties": {"bot": {"type": "boolean", "description": "Whether the user should be marked as a bot"}}, - "required": ["bot"] - }, - "ListUserChangeLogResponseSchema": { - "type": "object", - "properties": { - "entries": { - "type": "array", - "items": { - "type": "object", - "properties": { - "event_id": {"type": "string"}, - "field": {"type": "string"}, - "old_value": {"nullable": true, "type": "string"}, - "new_value": {"nullable": true, "type": "string"}, - "reason": {"nullable": true, "type": "string"}, - "actor_user_id": {"nullable": true, "type": "string"}, - "event_at": {"type": "string"} - }, - "required": ["event_id", "field", "old_value", "new_value", "reason", "actor_user_id", "event_at"] - }, - "maxItems": 200 - }, - "next_page_token": {"nullable": true, "type": "string"} - }, - "required": ["entries", "next_page_token"] - }, - "AdminUserDobUpdateRequest": { - "type": "object", - "properties": {"date_of_birth": {"type": "string", "description": "New date of birth in YYYY-MM-DD format"}}, - "required": ["date_of_birth"] - }, - "AdminUserDeletionScheduleRequest": { - "type": "object", - "properties": { - "reason_code": { - "$ref": "#/components/schemas/DeletionReasonCode", - "description": "Code indicating the reason for deletion" - }, - "public_reason": {"type": "string", "description": "Public-facing reason for the deletion"}, - "days_until_deletion": { - "type": "integer", - "minimum": 1, - "maximum": 365, - "format": "int32", - "description": "Number of days until the account is deleted" - } - }, - "required": ["reason_code"] - }, - "AdminUserDmChannelListResponse": { - "oneOf": [ + "x-bitflagValues": [ + {"name": "DISCRIMINATOR", "value": "1", "description": "User has a premium discriminator"}, + {"name": "BADGE_HIDDEN", "value": "2", "description": "User has hidden their premium badge"}, + {"name": "BADGE_MASKED", "value": "4", "description": "User has masked their premium badge"}, { - "type": "object", - "properties": { - "channels": { - "type": "array", - "items": { - "type": "object", - "properties": { - "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "channel_type": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, - "channel_nsfw": {"nullable": true, "type": "boolean"}, - "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, - "recipient_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 100 - }, - "recipients": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "username": {"type": "string"}, - "discriminator": {"type": "string"}, - "global_name": {"nullable": true, "type": "string"}, - "avatar": {"nullable": true, "type": "string"} - }, - "required": ["id", "username", "discriminator", "global_name", "avatar"] - }, - "maxItems": 100 - }, - "last_message_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "is_open": {"type": "boolean"}, - "name": {"nullable": true, "type": "string"}, - "icon": {"nullable": true, "type": "string"}, - "owner_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]} - }, - "required": [ - "channel_id", - "channel_type", - "channel_nsfw", - "guild_nsfw_level", - "recipient_ids", - "recipients", - "last_message_id", - "is_open", - "name", - "icon", - "owner_id" - ] - }, - "maxItems": 200 - } - }, - "required": ["channels"] + "name": "BADGE_TIMESTAMP_HIDDEN", + "value": "8", + "description": "User has hidden their premium badge timestamp" }, { - "type": "object", - "properties": { - "channels": { - "type": "array", - "items": { - "type": "object", - "properties": { - "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "channel_type": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]}, - "channel_nsfw": {"nullable": true, "type": "boolean"}, - "guild_nsfw_level": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/NSFWLevel"}]}, - "recipient_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 100 - }, - "recipients": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, - "username": {"type": "string"}, - "discriminator": {"type": "string"}, - "global_name": {"nullable": true, "type": "string"}, - "avatar": {"nullable": true, "type": "string"} - }, - "required": ["id", "username", "discriminator", "global_name", "avatar"] - }, - "maxItems": 100 - }, - "last_message_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]}, - "is_open": {"type": "boolean"}, - "name": {"nullable": true, "type": "string"}, - "icon": {"nullable": true, "type": "string"}, - "owner_id": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]} - }, - "required": [ - "channel_id", - "channel_type", - "channel_nsfw", - "guild_nsfw_level", - "recipient_ids", - "recipients", - "last_message_id", - "is_open", - "name", - "icon", - "owner_id" - ] - }, - "maxItems": 500 - } - }, - "required": ["channels"] - } + "name": "BADGE_SEQUENCE_HIDDEN", + "value": "16", + "description": "User has hidden their premium badge sequence" + }, + {"name": "PERKS_SANITIZED", "value": "32", "description": "User premium perks are sanitized"}, + {"name": "PURCHASE_DISABLED", "value": "64", "description": "Premium purchase is disabled for this user"}, + {"name": "ENABLED_OVERRIDE", "value": "128", "description": "Premium status is enabled via override"}, + {"name": "PERKS_DISABLED", "value": "256", "description": "User has temporarily disabled premium perks"} ] }, - "AdminUserDmChannelType": { - "type": "string", - "enum": ["dm", "group_dm"], - "description": "Kind of direct message channel to list" - }, - "AdminUserEmailUpdateRequest": { - "type": "object", - "properties": {"email": {"$ref": "#/components/schemas/EmailType"}}, - "required": ["email"] - }, - "AdminUserFlagsUpdateRequest": { - "type": "object", - "properties": { - "add_flags": { - "type": "array", - "items": {"$ref": "#/components/schemas/UserFlags"}, - "maxItems": 64, - "description": "User flags to add" - }, - "remove_flags": { - "type": "array", - "items": {"$ref": "#/components/schemas/UserFlags"}, - "maxItems": 64, - "description": "User flags to remove" - } - } - }, - "ListUserGuildsResponse": { - "type": "object", - "properties": {"guilds": {"type": "array", "items": {"$ref": "#/components/schemas/GuildAdminResponse"}}}, - "required": ["guilds"] - }, - "MessageShredResponse": { - "type": "object", - "properties": { - "success": {"type": "boolean", "enum": [true]}, - "job_id": {"type": "string"}, - "requested": {"type": "integer", "minimum": 0, "maximum": 9007199254740991, "format": "int53"} - }, - "required": ["success", "job_id"] - }, - "AdminUserMessageShredRequest": { - "type": "object", - "properties": { - "entries": { - "type": "array", - "items": { - "type": "object", - "properties": { - "channel_id": {"$ref": "#/components/schemas/SnowflakeType"}, - "message_id": {"$ref": "#/components/schemas/SnowflakeType"} - }, - "required": ["channel_id", "message_id"] - }, - "minItems": 1, - "maxItems": 1000 - } - }, - "required": ["entries"] - }, - "DeleteAllUserMessagesResponse": { - "type": "object", - "properties": { - "success": {"type": "boolean", "enum": [true]}, - "dry_run": {"type": "boolean"}, - "channel_count": {"$ref": "#/components/schemas/Int32Type"}, - "message_count": {"$ref": "#/components/schemas/Int32Type"}, - "job_id": {"type": "string"} - }, - "required": ["success", "dry_run", "channel_count", "message_count"] - }, - "AdminUserPhoneVerificationRequest": { - "type": "object", - "properties": { - "has_verified_phone": { - "type": "boolean", - "description": "Whether the user should be treated as having completed phone verification" - } - }, - "required": ["has_verified_phone"] - }, - "AdminUserPremiumFlagsUpdateRequest": { - "type": "object", - "properties": { - "add_flags": { - "type": "array", - "items": {"$ref": "#/components/schemas/PremiumFlags"}, - "maxItems": 64, - "description": "Premium flags to add" - }, - "remove_flags": { - "type": "array", - "items": {"$ref": "#/components/schemas/PremiumFlags"}, - "maxItems": 64, - "description": "Premium flags to remove" - } - } - }, - "AdminUserClearFieldsRequest": { - "type": "object", - "properties": { - "fields": { - "type": "array", - "items": { - "type": "string", - "enum": ["avatar", "banner", "bio", "pronouns", "global_name"], - "description": "User profile field that can be cleared" - }, - "maxItems": 10, - "description": "List of profile fields to clear" - } - }, - "required": ["fields"] - }, - "ListUserRelationshipsResponse": { - "type": "object", - "properties": { - "friends": {"type": "array", "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"}}, - "incoming_requests": { - "type": "array", - "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"} - }, - "outgoing_requests": { - "type": "array", - "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"} - }, - "blocked": {"type": "array", "items": {"$ref": "#/components/schemas/AdminRelationshipEntrySchema"}} - }, - "required": ["friends", "incoming_requests", "outgoing_requests", "blocked"] - }, "AdminRelationshipEntrySchema": { "type": "object", "properties": { - "target_user_id": {"$ref": "#/components/schemas/SnowflakeType"}, + "target_user_id": {"$ref": "#/components/schemas/SnowflakeStringType"}, "category": {"$ref": "#/components/schemas/RelationshipCategoryEnum"}, "nickname": {"nullable": true, "type": "string"}, "since": {"nullable": true, "type": "string"}, @@ -13793,205 +15519,31 @@ "nullable": true, "type": "object", "properties": { - "id": {"$ref": "#/components/schemas/SnowflakeType"}, + "id": {"$ref": "#/components/schemas/SnowflakeStringType"}, "username": {"type": "string"}, "discriminator": {"type": "string"}, "global_name": {"nullable": true, "type": "string"}, "avatar": {"nullable": true, "type": "string"} }, - "required": ["id", "username", "discriminator", "global_name", "avatar"] + "required": ["id", "username", "discriminator", "global_name", "avatar"], + "additionalProperties": false } }, - "required": ["target_user_id", "category", "nickname", "since", "target"] - }, - "RelationshipCategoryEnum": { - "enum": ["friend", "incoming_request", "outgoing_request", "blocked"], - "type": "string" - }, - "RemoveUserRelationshipsResponse": { - "type": "object", - "properties": {"removed_count": {"$ref": "#/components/schemas/Int32Type"}}, - "required": ["removed_count"] - }, - "ListUserSessionsResponse": { - "type": "object", - "properties": { - "sessions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "session_id_hash": {"type": "string", "description": "Hashed session identifier (base64url)"}, - "created_at": {"type": "string", "description": "ISO timestamp when the session was created"}, - "approx_last_used_at": { - "type": "string", - "description": "ISO timestamp of the session last usage (approximate)" - }, - "client_ip": {"type": "string", "description": "Client IP address"}, - "client_ip_reverse": { - "description": "Reverse DNS hostname for the client IP (PTR), if available", - "nullable": true, - "type": "string" - }, - "client_os": { - "description": "Client operating system, if detected", - "nullable": true, - "type": "string" - }, - "client_platform": {"description": "Client platform, if detected", "nullable": true, "type": "string"}, - "client_location": { - "description": "Approximate geo location label for the client IP, if available", - "nullable": true, - "type": "string" - }, - "deleted_at": { - "description": "ISO timestamp when the session was terminated, or null if still active", - "nullable": true, - "type": "string" - } - }, - "required": [ - "session_id_hash", - "created_at", - "approx_last_used_at", - "client_ip", - "client_ip_reverse", - "client_os", - "client_platform", - "client_location", - "deleted_at" - ] - } - } - }, - "required": ["sessions"] - }, - "TerminateSessionsResponse": { - "type": "object", - "properties": {"terminated_count": {"$ref": "#/components/schemas/Int32Type"}}, - "required": ["terminated_count"] - }, - "AdminUserSuspiciousDisableRequest": { - "type": "object", - "properties": {"flags": {"$ref": "#/components/schemas/SuspiciousActivityFlags"}}, - "required": ["flags"] - }, - "AdminUserSuspiciousActivityFlagsRequest": { - "type": "object", - "properties": {"flags": {"$ref": "#/components/schemas/SuspiciousActivityFlags"}}, - "required": ["flags"] - }, - "AdminUserSystemStatusRequest": { - "type": "object", - "properties": { - "system": {"type": "boolean", "description": "Whether the user should be marked as a system user"} - }, - "required": ["system"] - }, - "AdminUserTraitsRequest": { - "type": "object", - "properties": { - "traits": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "List of traits to assign to the user" - } - }, - "required": ["traits"] - }, - "AdminUserUsernameUpdateRequest": { - "type": "object", - "properties": { - "username": {"$ref": "#/components/schemas/UsernameType"}, - "discriminator": {"$ref": "#/components/schemas/DiscriminatorType"} - }, - "required": ["username"] - }, - "UsernameType": {"type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[a-zA-Z0-9_]+$"}, - "DiscriminatorType": {"type": "string", "pattern": "^\\d{1,4}$"}, - "WebAuthnCredentialListResponse": { - "type": "array", - "items": {"$ref": "#/components/schemas/WebAuthnCredentialResponse"} + "required": ["target_user_id", "category", "nickname", "since", "target"], + "additionalProperties": false }, + "DiscriminatorType": {"anyOf": [{"type": "string"}, {"type": "number"}]}, + "UsernameType": {"type": "string"}, "WebAuthnCredentialResponse": { "type": "object", "properties": { "id": {"type": "string", "description": "The credential ID"}, "name": {"type": "string", "description": "User-assigned name for the credential"}, "created_at": {"type": "string", "description": "When the credential was registered"}, - "last_used_at": {"description": "When the credential was last used", "nullable": true, "type": "string"} + "last_used_at": {"nullable": true, "description": "When the credential was last used", "type": "string"} }, - "required": ["id", "name", "created_at", "last_used_at"] - }, - "ListVoiceRegionsResponse": { - "type": "object", - "properties": { - "regions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"type": "string", "description": "Unique identifier for the voice region"}, - "name": {"type": "string", "description": "Display name of the voice region"}, - "emoji": {"type": "string", "description": "Emoji representing the region"}, - "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, - "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, - "is_default": {"type": "boolean", "description": "Whether this is the default region"}, - "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this region" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this region" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this region" - }, - "created_at": { - "description": "ISO 8601 timestamp when the region was created", - "nullable": true, - "type": "string" - }, - "updated_at": { - "description": "ISO 8601 timestamp when the region was last updated", - "nullable": true, - "type": "string" - }, - "servers": { - "type": "array", - "items": {"$ref": "#/components/schemas/VoiceServerAdminResponse"}, - "description": "Voice servers in this region" - } - }, - "required": [ - "id", - "name", - "emoji", - "latitude", - "longitude", - "is_default", - "vip_only", - "required_guild_features", - "allowed_guild_ids", - "allowed_user_ids", - "created_at", - "updated_at" - ] - }, - "description": "List of voice regions" - } - }, - "required": ["regions"] + "required": ["id", "name", "created_at", "last_used_at"], + "additionalProperties": false }, "VoiceServerAdminResponse": { "type": "object", @@ -14004,51 +15556,50 @@ "description": "Client signal WebSocket endpoint URL for the voice server" }, "latitude": { - "description": "Optional geographic latitude override for this server", "nullable": true, + "description": "Optional geographic latitude override for this server", "type": "number" }, "longitude": { - "description": "Optional geographic longitude override for this server", "nullable": true, + "description": "Optional geographic longitude override for this server", "type": "number" }, "is_active": {"type": "boolean", "description": "Whether the server is currently active"}, "soft_connection_limit": { - "description": "Connection count above which placement prefers another server, or null when the server has no limit", "nullable": true, + "description": "Connection count above which placement prefers another server, or null when the server has no limit", "type": "integer", "minimum": 1, - "maximum": 2147483647, - "format": "int32" + "maximum": 2147483647 }, "vip_only": {"type": "boolean", "description": "Whether this server is restricted to VIP users"}, "required_guild_features": { + "maxItems": 100, "type": "array", "items": {"type": "string"}, - "maxItems": 100, "description": "Guild features required to use this server" }, "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, "description": "Guild IDs explicitly allowed to use this server" }, "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, "description": "User IDs explicitly allowed to use this server" }, "created_at": { - "description": "ISO 8601 timestamp when the server was created", "nullable": true, + "description": "ISO 8601 timestamp when the server was created", "type": "string" }, "updated_at": { - "description": "ISO 8601 timestamp when the server was last updated", "nullable": true, + "description": "ISO 8601 timestamp when the server was last updated", "type": "string" } }, @@ -14066,70 +15617,10 @@ "allowed_user_ids", "created_at", "updated_at" - ] + ], + "additionalProperties": false }, - "CreateVoiceRegionResponse": { - "type": "object", - "properties": { - "region": { - "type": "object", - "properties": { - "id": {"type": "string", "description": "Unique identifier for the voice region"}, - "name": {"type": "string", "description": "Display name of the voice region"}, - "emoji": {"type": "string", "description": "Emoji representing the region"}, - "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, - "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, - "is_default": {"type": "boolean", "description": "Whether this is the default region"}, - "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this region" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this region" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this region" - }, - "created_at": { - "description": "ISO 8601 timestamp when the region was created", - "nullable": true, - "type": "string" - }, - "updated_at": { - "description": "ISO 8601 timestamp when the region was last updated", - "nullable": true, - "type": "string" - } - }, - "required": [ - "id", - "name", - "emoji", - "latitude", - "longitude", - "is_default", - "vip_only", - "required_guild_features", - "allowed_guild_ids", - "allowed_user_ids", - "created_at", - "updated_at" - ], - "description": "Created voice region" - } - }, - "required": ["region"] - }, - "CreateVoiceRegionRequest": { + "VoiceRegionAdminResponse": { "type": "object", "properties": { "id": {"type": "string", "description": "Unique identifier for the voice region"}, @@ -14140,481 +15631,49 @@ "is_default": {"type": "boolean", "description": "Whether this is the default region"}, "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, "required_guild_features": { + "maxItems": 100, "type": "array", "items": {"type": "string"}, - "maxItems": 100, "description": "Guild features required to use this region" }, "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, "description": "Guild IDs explicitly allowed to use this region" }, "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, "maxItems": 1000, + "type": "array", + "items": {"$ref": "#/components/schemas/SnowflakeStringType"}, "description": "User IDs explicitly allowed to use this region" - } - }, - "required": ["id", "name", "emoji", "latitude", "longitude"] - }, - "GetVoiceRegionResponse": { - "type": "object", - "properties": { - "region": { - "description": "Voice region details or null if not found", + }, + "created_at": { "nullable": true, - "type": "object", - "properties": { - "id": {"type": "string", "description": "Unique identifier for the voice region"}, - "name": {"type": "string", "description": "Display name of the voice region"}, - "emoji": {"type": "string", "description": "Emoji representing the region"}, - "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, - "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, - "is_default": {"type": "boolean", "description": "Whether this is the default region"}, - "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this region" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this region" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this region" - }, - "created_at": { - "description": "ISO 8601 timestamp when the region was created", - "nullable": true, - "type": "string" - }, - "updated_at": { - "description": "ISO 8601 timestamp when the region was last updated", - "nullable": true, - "type": "string" - }, - "servers": { - "type": "array", - "items": {"$ref": "#/components/schemas/VoiceServerAdminResponse"}, - "description": "Voice servers in this region" - } - }, - "required": [ - "id", - "name", - "emoji", - "latitude", - "longitude", - "is_default", - "vip_only", - "required_guild_features", - "allowed_guild_ids", - "allowed_user_ids", - "created_at", - "updated_at" - ] - } - }, - "required": ["region"] - }, - "UpdateVoiceRegionResponse": { - "type": "object", - "properties": { - "region": { - "type": "object", - "properties": { - "id": {"type": "string", "description": "Unique identifier for the voice region"}, - "name": {"type": "string", "description": "Display name of the voice region"}, - "emoji": {"type": "string", "description": "Emoji representing the region"}, - "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, - "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, - "is_default": {"type": "boolean", "description": "Whether this is the default region"}, - "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this region" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this region" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this region" - }, - "created_at": { - "description": "ISO 8601 timestamp when the region was created", - "nullable": true, - "type": "string" - }, - "updated_at": { - "description": "ISO 8601 timestamp when the region was last updated", - "nullable": true, - "type": "string" - } - }, - "required": [ - "id", - "name", - "emoji", - "latitude", - "longitude", - "is_default", - "vip_only", - "required_guild_features", - "allowed_guild_ids", - "allowed_user_ids", - "created_at", - "updated_at" - ], - "description": "Updated voice region" - } - }, - "required": ["region"] - }, - "UpdateVoiceRegionRequest": { - "type": "object", - "properties": { - "id": {"type": "string", "description": "Unique identifier for the voice region"}, - "name": {"type": "string", "description": "Display name of the voice region"}, - "emoji": {"type": "string", "description": "Emoji representing the region"}, - "latitude": {"type": "number", "description": "Geographic latitude coordinate"}, - "longitude": {"type": "number", "description": "Geographic longitude coordinate"}, - "is_default": {"type": "boolean", "description": "Whether this is the default region"}, - "vip_only": {"type": "boolean", "description": "Whether this region is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this region" + "description": "ISO 8601 timestamp when the region was created", + "type": "string" }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this region" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this region" - } - }, - "required": ["id"] - }, - "DeleteVoiceResponse": { - "type": "object", - "properties": {"success": {"type": "boolean", "description": "Whether the deletion was successful"}}, - "required": ["success"] - }, - "ListVoiceServersResponse": { - "type": "object", - "properties": { - "servers": { - "type": "array", - "items": {"$ref": "#/components/schemas/VoiceServerAdminResponse"}, - "description": "List of voice servers" - } - }, - "required": ["servers"] - }, - "CreateVoiceServerResponse": { - "type": "object", - "properties": { - "server": { - "type": "object", - "properties": { - "region_id": {"type": "string", "description": "ID of the region this server belongs to"}, - "server_id": {"type": "string", "description": "Unique identifier for the voice server"}, - "endpoint": { - "type": "string", - "format": "uri", - "description": "Client signal WebSocket endpoint URL for the voice server" - }, - "latitude": { - "description": "Optional geographic latitude override for this server", - "nullable": true, - "type": "number" - }, - "longitude": { - "description": "Optional geographic longitude override for this server", - "nullable": true, - "type": "number" - }, - "is_active": {"type": "boolean", "description": "Whether the server is currently active"}, - "soft_connection_limit": { - "description": "Connection count above which placement prefers another server, or null when the server has no limit", - "nullable": true, - "type": "integer", - "minimum": 1, - "maximum": 2147483647, - "format": "int32" - }, - "vip_only": {"type": "boolean", "description": "Whether this server is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this server" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this server" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this server" - }, - "created_at": { - "description": "ISO 8601 timestamp when the server was created", - "nullable": true, - "type": "string" - }, - "updated_at": { - "description": "ISO 8601 timestamp when the server was last updated", - "nullable": true, - "type": "string" - } - }, - "required": [ - "region_id", - "server_id", - "endpoint", - "latitude", - "longitude", - "is_active", - "soft_connection_limit", - "vip_only", - "required_guild_features", - "allowed_guild_ids", - "allowed_user_ids", - "created_at", - "updated_at" - ], - "description": "Created voice server" - } - }, - "required": ["server"] - }, - "CreateVoiceServerRequest": { - "type": "object", - "properties": { - "region_id": {"type": "string", "description": "ID of the region this server belongs to"}, - "server_id": {"type": "string", "description": "Unique identifier for the voice server"}, - "endpoint": { - "type": "string", - "format": "uri", - "description": "Client signal WebSocket endpoint URL for the voice server" - }, - "api_key": {"type": "string", "description": "API key for authenticating with the voice server"}, - "api_secret": {"type": "string", "description": "API secret for authenticating with the voice server"}, - "latitude": { - "description": "Optional geographic latitude override for this server", + "updated_at": { "nullable": true, - "type": "number" - }, - "longitude": { - "description": "Optional geographic longitude override for this server", - "nullable": true, - "type": "number" - }, - "is_active": {"type": "boolean", "description": "Whether the server is currently active"}, - "soft_connection_limit": { - "description": "Connection count above which placement prefers another server, or null for no limit", - "nullable": true, - "type": "integer", - "minimum": 1, - "maximum": 2147483647, - "format": "int32" - }, - "vip_only": {"type": "boolean", "description": "Whether this server is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this server" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this server" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this server" + "description": "ISO 8601 timestamp when the region was last updated", + "type": "string" } }, - "required": ["region_id", "server_id", "endpoint", "api_key", "api_secret"] - }, - "GetVoiceServerResponse": { - "type": "object", - "properties": { - "server": { - "description": "Voice server details or null if not found", - "nullable": true, - "allOf": [{"$ref": "#/components/schemas/VoiceServerAdminResponse"}] - } - }, - "required": ["server"] - }, - "UpdateVoiceServerResponse": { - "type": "object", - "properties": { - "server": { - "type": "object", - "properties": { - "region_id": {"type": "string", "description": "ID of the region this server belongs to"}, - "server_id": {"type": "string", "description": "Unique identifier for the voice server"}, - "endpoint": { - "type": "string", - "format": "uri", - "description": "Client signal WebSocket endpoint URL for the voice server" - }, - "latitude": { - "description": "Optional geographic latitude override for this server", - "nullable": true, - "type": "number" - }, - "longitude": { - "description": "Optional geographic longitude override for this server", - "nullable": true, - "type": "number" - }, - "is_active": {"type": "boolean", "description": "Whether the server is currently active"}, - "soft_connection_limit": { - "description": "Connection count above which placement prefers another server, or null when the server has no limit", - "nullable": true, - "type": "integer", - "minimum": 1, - "maximum": 2147483647, - "format": "int32" - }, - "vip_only": {"type": "boolean", "description": "Whether this server is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this server" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this server" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this server" - }, - "created_at": { - "description": "ISO 8601 timestamp when the server was created", - "nullable": true, - "type": "string" - }, - "updated_at": { - "description": "ISO 8601 timestamp when the server was last updated", - "nullable": true, - "type": "string" - } - }, - "required": [ - "region_id", - "server_id", - "endpoint", - "latitude", - "longitude", - "is_active", - "soft_connection_limit", - "vip_only", - "required_guild_features", - "allowed_guild_ids", - "allowed_user_ids", - "created_at", - "updated_at" - ], - "description": "Updated voice server" - } - }, - "required": ["server"] - }, - "UpdateVoiceServerRequest": { - "type": "object", - "properties": { - "region_id": {"type": "string", "description": "ID of the region this server belongs to"}, - "server_id": {"type": "string", "description": "Unique identifier for the voice server"}, - "endpoint": { - "type": "string", - "format": "uri", - "description": "Client signal WebSocket endpoint URL for the voice server" - }, - "api_key": {"type": "string", "description": "API key for authenticating with the voice server"}, - "api_secret": {"type": "string", "description": "API secret for authenticating with the voice server"}, - "latitude": { - "description": "Optional geographic latitude override for this server", - "nullable": true, - "type": "number" - }, - "longitude": { - "description": "Optional geographic longitude override for this server", - "nullable": true, - "type": "number" - }, - "is_active": {"type": "boolean", "description": "Whether the server is currently active"}, - "soft_connection_limit": { - "description": "Connection count above which placement prefers another server, or null for no limit", - "nullable": true, - "type": "integer", - "minimum": 1, - "maximum": 2147483647, - "format": "int32" - }, - "vip_only": {"type": "boolean", "description": "Whether this server is restricted to VIP users"}, - "required_guild_features": { - "type": "array", - "items": {"type": "string"}, - "maxItems": 100, - "description": "Guild features required to use this server" - }, - "allowed_guild_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "Guild IDs explicitly allowed to use this server" - }, - "allowed_user_ids": { - "type": "array", - "items": {"$ref": "#/components/schemas/SnowflakeType"}, - "maxItems": 1000, - "description": "User IDs explicitly allowed to use this server" - } - }, - "required": ["region_id", "server_id"] + "required": [ + "id", + "name", + "emoji", + "latitude", + "longitude", + "is_default", + "vip_only", + "required_guild_features", + "allowed_guild_ids", + "allowed_user_ids", + "created_at", + "updated_at" + ], + "additionalProperties": false } }, "securitySchemes": { diff --git a/fluxer_admin/src/api/admin_api_keys.rs b/fluxer_admin/src/api/admin_api_keys.rs index cdb1a454c..0ba1fd738 100644 --- a/fluxer_admin/src/api/admin_api_keys.rs +++ b/fluxer_admin/src/api/admin_api_keys.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{CreateAdminApiKeyResponse, ListAdminApiKeyEntry}; @@ -35,7 +35,7 @@ impl AdminApiClient { } pub async fn revoke_api_key(&self, key_id: &str) -> ApiResult<()> { - let key_id = generated_types::SnowflakeType::from(key_id.to_owned()); + let key_id = snowflake(key_id); self.generated() .delete_admin_api_key(&key_id) .await diff --git a/fluxer_admin/src/api/archives.rs b/fluxer_admin/src/api/archives.rs index 71676c9de..0a0f1e302 100644 --- a/fluxer_admin/src/api/archives.rs +++ b/fluxer_admin/src/api/archives.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{Archive, ArchiveDownloadUrlResponse, ListArchivesResponse}; @@ -12,7 +12,7 @@ impl AdminApiClient { include_attachments: bool, ) -> ApiResult { let body = generated_types::AdminArchiveCreateRequest { - include_attachments: include_attachments.then_some(true), + include_attachments, }; let response = self .generated() @@ -28,7 +28,7 @@ impl AdminApiClient { include_attachments: bool, ) -> ApiResult { let body = generated_types::AdminArchiveCreateRequest { - include_attachments: include_attachments.then_some(true), + include_attachments, }; let response = self .generated() @@ -78,15 +78,17 @@ impl AdminApiClient { subject_id: &str, archive_id: &str, ) -> ApiResult { + let subject_type = generated_types::ArchiveSubjectTypeSchema::try_from(subject_type) + .map_err(|e| ApiError::Parse(e.to_string()))?; let response = self .generated() - .get_admin_archive_download(subject_type, subject_id, archive_id) + .get_admin_archive_download( + subject_type, + &snowflake(subject_id), + &snowflake(archive_id), + ) .await .map_err(|e| self.generated_error(e))?; self.generated_value(response.into_inner()) } } - -fn snowflake(value: &str) -> generated_types::SnowflakeType { - generated_types::SnowflakeType::from(value.to_owned()) -} diff --git a/fluxer_admin/src/api/assets.rs b/fluxer_admin/src/api/assets.rs index 955904d67..b71c37ee5 100644 --- a/fluxer_admin/src/api/assets.rs +++ b/fluxer_admin/src/api/assets.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiResult}; @@ -13,10 +13,7 @@ impl AdminApiClient { let body = generated_types::PurgeGuildAssetsRequest { ids: ids.to_vec() }; let response = self .generated() - .purge_admin_guild_assets( - &generated_types::SnowflakeType::from(guild_id.to_owned()), - &body, - ) + .purge_admin_guild_assets(&snowflake(guild_id), &body) .await .map_err(|e| self.generated_error(e))?; self.generated_value(response.into_inner()) diff --git a/fluxer_admin/src/api/audit.rs b/fluxer_admin/src/api/audit.rs index c595881ee..47013ac0b 100644 --- a/fluxer_admin/src/api/audit.rs +++ b/fluxer_admin/src/api/audit.rs @@ -3,8 +3,6 @@ use crate::api::generated::types as generated_types; use super::client::{AdminApiClient, ApiError, ApiResult}; -#[cfg(test)] -use super::types::AuditLogEntry; use super::types::AuditLogsListResponse; pub struct SearchAuditLogsParams { @@ -38,67 +36,25 @@ impl AdminApiClient { let limit = params.limit.to_string(); let offset = params.offset.to_string(); let query_params = [ - ( - "q", - nonempty_string(params.query.as_deref()).unwrap_or_default(), - ), + ("q", params.query.as_deref().unwrap_or_default()), ( "admin_user_id", - nonempty_string(params.admin_user_id.as_deref()).unwrap_or_default(), + params.admin_user_id.as_deref().unwrap_or_default(), ), ( "target_type", - nonempty_string(params.target_type.as_deref()).unwrap_or_default(), + params.target_type.as_deref().unwrap_or_default(), ), - ( - "target_id", - nonempty_string(params.target_id.as_deref()).unwrap_or_default(), - ), - ("sort_by", sort_by.unwrap_or_default()), - ("sort_order", sort_order.unwrap_or_default()), - ("limit", limit), - ("offset", offset), + ("target_id", params.target_id.as_deref().unwrap_or_default()), + ("sort_by", sort_by.as_deref().unwrap_or_default()), + ("sort_order", sort_order.as_deref().unwrap_or_default()), + ("limit", limit.as_str()), + ("offset", offset.as_str()), ]; - let query_params: Vec<(&str, &str)> = query_params - .iter() - .map(|(key, value)| (*key, value.as_str())) - .collect(); self.get("/admin/audit-logs", Some(&query_params)).await } } -#[cfg(test)] -fn audit_logs_response( - response: generated_types::AuditLogsListResponseSchema, -) -> ApiResult { - Ok(AuditLogsListResponse { - logs: response.logs.into_iter().map(audit_log_entry).collect(), - total: crate::api::generated::number_to_u64(response.total, "total") - .map_err(ApiError::Parse)?, - }) -} - -#[cfg(test)] -fn audit_log_entry(entry: generated_types::AdminAuditLogResponseSchema) -> AuditLogEntry { - AuditLogEntry { - log_id: String::from(entry.log_id), - admin_user_id: String::from(entry.admin_user_id), - admin_user: None, - action: entry.action, - target_id: entry.target_id, - target_type: entry.target_type, - target_user: None, - target_guild: None, - target_channel: None, - related_users: Default::default(), - related_guilds: Default::default(), - related_channels: Default::default(), - audit_log_reason: entry.audit_log_reason, - metadata: entry.metadata, - created_at: entry.created_at, - } -} - fn audit_sort_by(value: &str) -> ApiResult { let value = match value { "created_at" => "createdAt", @@ -113,12 +69,6 @@ fn audit_sort_order(value: &str) -> ApiResult) -> Option { - value - .filter(|value| !value.is_empty()) - .map(std::borrow::ToOwned::to_owned) -} - #[cfg(test)] mod tests { use super::*; @@ -135,10 +85,39 @@ mod tests { #[test] fn rejects_lossy_audit_totals() { - let response = generated_types::AuditLogsListResponseSchema { - logs: Vec::new(), - total: 1.5, - }; - assert!(audit_logs_response(response).is_err()); + for total in [serde_json::json!(1.5), serde_json::json!(-1)] { + let response = serde_json::json!({"logs": [], "total": total}); + assert!(serde_json::from_value::(response).is_err()); + } + } + + #[test] + fn deserializes_audit_fields_without_losing_generated_string_values() { + let json = serde_json::json!({ + "logs": [{ + "log_id": "123456789012345678", + "admin_user_id": "234567890123456789", + "admin_user": null, + "action": "USER_UPDATE", + "target_id": "345678901234567890", + "target_type": "user", + "target_user": null, + "target_guild": null, + "target_channel": null, + "related_users": {}, + "related_guilds": {}, + "related_channels": {}, + "audit_log_reason": "Account review", + "metadata": {"field": "username"}, + "created_at": "2026-09-11T12:00:00.000Z" + }], + "total": 1 + }); + let generated: generated_types::AuditLogsListResponseSchema = + serde_json::from_value(json.clone()).unwrap(); + assert_eq!(generated.logs[0].action.to_string(), "USER_UPDATE"); + + let response: AuditLogsListResponse = serde_json::from_value(json.clone()).unwrap(); + assert_eq!(serde_json::to_value(response).unwrap(), json); } } diff --git a/fluxer_admin/src/api/bans.rs b/fluxer_admin/src/api/bans.rs index cd31db90b..80c411eeb 100644 --- a/fluxer_admin/src/api/bans.rs +++ b/fluxer_admin/src/api/bans.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{BanAvatarResult, BanCheckResult, BulkBanResult}; @@ -9,10 +9,12 @@ impl AdminApiClient { pub async fn ban_email(&self, email: &str) -> ApiResult<()> { self.create_blocklist_entry( "email", - generated_types::BanEmailRequest { - email: generated_types::EmailType::from(email.to_owned()), - } - .into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_1: Some(generated_types::BanEmailRequest { + email: generated_types::EmailType::from(email.to_owned()), + }), + ..Default::default() + }, ) .await } @@ -28,7 +30,10 @@ impl AdminApiClient { pub async fn ban_ip(&self, ip: &str) -> ApiResult<()> { self.create_blocklist_entry( "ip", - generated_types::BanIpRequest { ip: ip.to_owned() }.into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_0: Some(generated_types::BanIpRequest { ip: ip.to_owned() }), + ..Default::default() + }, ) .await } @@ -44,7 +49,10 @@ impl AdminApiClient { pub async fn add_suspicious_email_domain(&self, domain: &str) -> ApiResult<()> { self.create_blocklist_entry( SUSPICIOUS_EMAIL_DOMAIN_LIST, - suspicious_email_domain_request(domain)?.into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_2: Some(suspicious_email_domain_request(domain)?), + ..Default::default() + }, ) .await } @@ -62,10 +70,12 @@ impl AdminApiClient { pub async fn ban_phrase(&self, phrase: &str) -> ApiResult<()> { self.create_blocklist_entry( "phrase", - generated_types::BanPhraseRequest { - phrase: phrase.to_owned(), - } - .into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_3: Some(generated_types::BanPhraseRequest { + phrase: phrase.to_owned(), + }), + ..Default::default() + }, ) .await } @@ -81,14 +91,16 @@ impl AdminApiClient { pub async fn ban_url(&self, url: &str) -> ApiResult<()> { self.create_blocklist_entry( "url", - generated_types::BanUrlRequest { - category: None, - notes: None, - severity: None, - source_url: None, - url: url.to_owned(), - } - .into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_4: Some(generated_types::BanUrlRequest { + category: None, + notes: None, + severity: None, + source_url: None, + url: url.to_owned(), + }), + ..Default::default() + }, ) .await } @@ -104,15 +116,17 @@ impl AdminApiClient { pub async fn ban_url_domain(&self, domain: &str, match_subdomains: bool) -> ApiResult<()> { self.create_blocklist_entry( "url-domain", - generated_types::BanUrlDomainRequest { - category: None, - domain: domain.to_owned(), - match_subdomains: Some(match_subdomains), - notes: None, - severity: None, - source_url: None, - } - .into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_5: Some(generated_types::BanUrlDomainRequest { + category: None, + domain: domain.to_owned(), + match_subdomains, + notes: None, + severity: None, + source_url: None, + }), + ..Default::default() + }, ) .await } @@ -131,16 +145,17 @@ impl AdminApiClient { sha256_hex: &str, audit_log_reason: Option<&str>, ) -> ApiResult<()> { - let body = generated_types::AdminBlocklistEntryCreateRequest::from( - generated_types::BanFileShaRequest { + let body = generated_types::AdminBlocklistEntryCreateRequest { + subtype_6: Some(generated_types::BanFileShaRequest { category: None, content_type: None, notes: None, severity: None, sha256_hex: sha256_hex.to_owned(), source_url: None, - }, - ); + }), + ..Default::default() + }; self.post_void_with_reason( "/admin/blocklists/file-sha/entries", Some(&serde_json::to_value(&body).map_err(|e| ApiError::Parse(e.to_string()))?), @@ -186,15 +201,17 @@ impl AdminApiClient { pub async fn ban_avatar_hash(&self, hash_short: &str) -> ApiResult<()> { self.create_blocklist_entry( "avatar-hash", - generated_types::BanAvatarHashRequest { - category: None, - hashes: vec![hash_short.to_owned()], - notes: None, - reason: None, - severity: None, - source_url: None, - } - .into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_7: Some(generated_types::BanAvatarHashRequest { + category: None, + hashes: vec![hash_short.to_owned()], + notes: None, + reason: None, + severity: None, + source_url: None, + }), + ..Default::default() + }, ) .await } @@ -213,10 +230,7 @@ impl AdminApiClient { let body = generated_types::BanUserAvatarRequest::default(); let response = self .generated() - .ban_admin_user_avatar( - &generated_types::SnowflakeType::from(user_id.to_owned()), - &body, - ) + .ban_admin_user_avatar(&snowflake(user_id), &body) .await .map_err(|e| self.generated_error(e))?; self.generated_value(response.into_inner()) @@ -225,7 +239,10 @@ impl AdminApiClient { pub async fn ban_profile_substring(&self, scope: &str, substring: &str) -> ApiResult<()> { self.create_blocklist_entry( PROFILE_SUBSTRING_LIST, - profile_substring_request(scope, substring)?.into(), + generated_types::AdminBlocklistEntryCreateRequest { + subtype_8: Some(profile_substring_request(scope, substring)?), + ..Default::default() + }, ) .await } @@ -249,6 +266,7 @@ impl AdminApiClient { list_type: &str, body: generated_types::AdminBlocklistEntryCreateRequest, ) -> ApiResult<()> { + let list_type = blocklist_list_type(list_type)?; self.generated() .create_admin_blocklist_entry(list_type, &body) .await @@ -262,6 +280,7 @@ impl AdminApiClient { entry_value: &str, scope: Option<&str>, ) -> ApiResult<()> { + let list_type = blocklist_list_type(list_type)?; let scope = scope.map(blocklist_delete_scope).transpose()?; self.generated() .delete_admin_blocklist_entry(list_type, entry_value, scope) @@ -276,6 +295,7 @@ impl AdminApiClient { entry_value: &str, scope: Option<&str>, ) -> ApiResult { + let list_type = blocklist_list_type(list_type)?; let scope = scope.map(blocklist_get_scope).transpose()?; let response = self .generated() @@ -290,6 +310,11 @@ const SUSPICIOUS_EMAIL_DOMAIN_LIST: &str = "email-domain-suspicious"; const PROFILE_SUBSTRING_LIST: &str = "profile-substring"; +fn blocklist_list_type(list_type: &str) -> ApiResult { + generated_types::AdminBlocklistListType::try_from(list_type) + .map_err(|e| ApiError::Parse(e.to_string())) +} + fn blocklist_entry_path(list_type: &str, entry_value: &str) -> String { format!( "/admin/blocklists/{}/entries/{}", diff --git a/fluxer_admin/src/api/bulk.rs b/fluxer_admin/src/api/bulk.rs index 48c7458a8..f6ed8409d 100644 --- a/fluxer_admin/src/api/bulk.rs +++ b/fluxer_admin/src/api/bulk.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::BulkJobResponse; @@ -13,15 +13,11 @@ impl AdminApiClient { remove_flags: &[String], audit_log_reason: Option<&str>, ) -> ApiResult { - let body = generated_types::AdminBulkJobCreateRequest::from( - generated_types::UpdateUserFlagsAdminBulkJobCreateRequest { - add_flags: user_flags(add_flags), - remove_flags: user_flags(remove_flags), - task: - generated_types::UpdateUserFlagsAdminBulkJobCreateRequestTask::UpdateUserFlags, - user_ids: snowflakes(user_ids), - }, - ); + let body = generated_types::AdminBulkJobCreateRequest::UpdateUserFlags { + add_flags: user_flags(add_flags), + remove_flags: user_flags(remove_flags), + user_ids: snowflakes(user_ids), + }; self.post_typed_with_reason("/admin/bulk-jobs", &body, audit_log_reason) .await } @@ -33,14 +29,11 @@ impl AdminApiClient { remove_flags: &[String], audit_log_reason: Option<&str>, ) -> ApiResult { - let body = generated_types::AdminBulkJobCreateRequest::from( - generated_types::UpdateSuspiciousActivityFlagsAdminBulkJobCreateRequest { - add_flags: add_flags.to_vec(), - remove_flags: remove_flags.to_vec(), - task: generated_types::UpdateSuspiciousActivityFlagsAdminBulkJobCreateRequestTask::UpdateSuspiciousActivityFlags, - user_ids: snowflakes(user_ids), - }, - ); + let body = generated_types::AdminBulkJobCreateRequest::UpdateSuspiciousActivityFlags { + add_flags: add_flags.to_vec(), + remove_flags: remove_flags.to_vec(), + user_ids: snowflakes(user_ids), + }; self.post_typed_with_reason("/admin/bulk-jobs", &body, audit_log_reason) .await } @@ -52,14 +45,11 @@ impl AdminApiClient { remove_features: &[String], audit_log_reason: Option<&str>, ) -> ApiResult { - let body = generated_types::AdminBulkJobCreateRequest::from( - generated_types::UpdateGuildFeaturesAdminBulkJobCreateRequest { - add_features: guild_features(add_features), - guild_ids: snowflakes(guild_ids), - remove_features: guild_features(remove_features), - task: generated_types::UpdateGuildFeaturesAdminBulkJobCreateRequestTask::UpdateGuildFeatures, - }, - ); + let body = generated_types::AdminBulkJobCreateRequest::UpdateGuildFeatures { + add_features: guild_features(add_features), + guild_ids: snowflakes(guild_ids), + remove_features: guild_features(remove_features), + }; self.post_typed_with_reason("/admin/bulk-jobs", &body, audit_log_reason) .await } @@ -70,14 +60,10 @@ impl AdminApiClient { user_ids: &[String], audit_log_reason: Option<&str>, ) -> ApiResult { - let body = generated_types::AdminBulkJobCreateRequest::from( - generated_types::AddGuildMembersAdminBulkJobCreateRequest { - guild_id: snowflake(guild_id), - task: - generated_types::AddGuildMembersAdminBulkJobCreateRequestTask::AddGuildMembers, - user_ids: snowflakes(user_ids), - }, - ); + let body = generated_types::AdminBulkJobCreateRequest::AddGuildMembers { + guild_id: snowflake(guild_id), + user_ids: snowflakes(user_ids), + }; self.post_typed_with_reason("/admin/bulk-jobs", &body, audit_log_reason) .await } @@ -87,13 +73,9 @@ impl AdminApiClient { user_ids: &[String], audit_log_reason: Option<&str>, ) -> ApiResult { - let body = generated_types::AdminBulkJobCreateRequest::from( - generated_types::DeleteUserMessagesAdminBulkJobCreateRequest { - task: - generated_types::DeleteUserMessagesAdminBulkJobCreateRequestTask::DeleteUserMessages, - user_ids: snowflakes(user_ids), - }, - ); + let body = generated_types::AdminBulkJobCreateRequest::DeleteUserMessages { + user_ids: snowflakes(user_ids), + }; self.post_typed_with_reason("/admin/bulk-jobs", &body, audit_log_reason) .await } @@ -106,37 +88,28 @@ impl AdminApiClient { public_reason: Option<&str>, audit_log_reason: Option<&str>, ) -> ApiResult { - let body = generated_types::AdminBulkJobCreateRequest::from( - generated_types::ScheduleUserDeletionAdminBulkJobCreateRequest { - days_until_deletion: Some( - crate::api::generated::nonzero_u32(days_until_deletion, "days_until_deletion") - .map_err(ApiError::Parse)?, - ), - public_reason: public_reason.map(std::borrow::ToOwned::to_owned), - reason_code: crate::api::generated::deletion_reason_code( - i32::try_from(reason_code).map_err(|e| ApiError::Parse(e.to_string()))?, - "reason_code", - ) - .map_err(ApiError::Parse)?, - task: generated_types::ScheduleUserDeletionAdminBulkJobCreateRequestTask::ScheduleUserDeletion, - user_ids: snowflakes(user_ids), - }, - ); + let body = generated_types::AdminBulkJobCreateRequest::ScheduleUserDeletion { + days_until_deletion: crate::api::generated::nonzero_u32( + days_until_deletion, + "days_until_deletion", + ) + .map_err(ApiError::Parse)? + .into(), + public_reason: public_reason.map(std::borrow::ToOwned::to_owned), + reason_code: crate::api::generated::deletion_reason_code( + i32::try_from(reason_code).map_err(|e| ApiError::Parse(e.to_string()))?, + "reason_code", + ) + .map_err(ApiError::Parse)?, + user_ids: snowflakes(user_ids), + }; self.post_typed_with_reason("/admin/bulk-jobs", &body, audit_log_reason) .await } } -fn snowflake(value: &str) -> generated_types::SnowflakeType { - generated_types::SnowflakeType::from(value.to_owned()) -} - fn snowflakes(values: &[String]) -> Vec { - values - .iter() - .cloned() - .map(generated_types::SnowflakeType::from) - .collect() + values.iter().map(|value| snowflake(value)).collect() } fn user_flags(values: &[String]) -> Vec { diff --git a/fluxer_admin/src/api/client.rs b/fluxer_admin/src/api/client.rs index a4b6885c2..8b66b3ab6 100644 --- a/fluxer_admin/src/api/client.rs +++ b/fluxer_admin/src/api/client.rs @@ -120,7 +120,7 @@ impl AdminApiClient { query_params: Option<&[(&str, &str)]>, ) -> ApiResult { let response = Self::send_request(self.request(Method::GET, path, query_params)).await?; - self.parse_response(response).await + Self::parse_response(response).await } pub async fn post( @@ -152,7 +152,7 @@ impl AdminApiClient { let builder = Self::with_audit_log_reason(self.request(Method::POST, path, None), audit_log_reason); let response = Self::send_request(builder.json(body)).await?; - self.parse_response(response).await + Self::parse_response(response).await } pub async fn post_with_reason( @@ -164,7 +164,7 @@ impl AdminApiClient { let builder = Self::with_audit_log_reason(self.request(Method::POST, path, None), audit_log_reason); let response = Self::send_request(Self::with_json_body(builder, body)).await?; - self.parse_response(response).await + Self::parse_response(response).await } pub async fn post_void(&self, path: &str, body: Option<&serde_json::Value>) -> ApiResult<()> { @@ -200,7 +200,7 @@ impl AdminApiClient { let builder = Self::with_audit_log_reason(self.request(Method::PATCH, path, None), audit_log_reason); let response = Self::send_request(Self::with_json_body(builder, body)).await?; - self.parse_response(response).await + Self::parse_response(response).await } pub async fn patch_typed_with_reason( @@ -216,7 +216,7 @@ impl AdminApiClient { let builder = Self::with_audit_log_reason(self.request(Method::PATCH, path, None), audit_log_reason); let response = Self::send_request(builder.json(body)).await?; - self.parse_response(response).await + Self::parse_response(response).await } pub async fn put_with_reason( @@ -228,7 +228,7 @@ impl AdminApiClient { let builder = Self::with_audit_log_reason(self.request(Method::PUT, path, None), audit_log_reason); let response = Self::send_request(Self::with_json_body(builder, body)).await?; - self.parse_response(response).await + Self::parse_response(response).await } pub async fn put_typed_with_reason( @@ -244,7 +244,7 @@ impl AdminApiClient { let builder = Self::with_audit_log_reason(self.request(Method::PUT, path, None), audit_log_reason); let response = Self::send_request(builder.json(body)).await?; - self.parse_response(response).await + Self::parse_response(response).await } pub async fn put_void_with_reason( @@ -284,22 +284,22 @@ impl AdminApiClient { let builder = Self::with_audit_log_reason(self.request(Method::DELETE, path, None), audit_log_reason); let response = Self::send_request(Self::with_json_body(builder, body)).await?; - self.parse_response(response).await + Self::parse_response(response).await } async fn parse_void_response(response: reqwest::Response) -> ApiResult<()> { + Self::check_response_status(response).await.map(drop) + } + + async fn check_response_status(response: reqwest::Response) -> ApiResult { if response.status().is_success() { - Ok(()) - } else { - let status = response.status().as_u16(); - let text = response.text().await.map_err(|error| { - ApiError::Network(format!("failed to read error response body: {error}")) - })?; - Err(ApiError::Http { - status, - message: text, - }) + return Ok(response); } + let status = response.status().as_u16(); + let message = response.text().await.map_err(|error| { + ApiError::Network(format!("failed to read error response body: {error}")) + })?; + Err(ApiError::Http { status, message }) } pub(crate) fn generated(&self) -> &crate::api::generated::GeneratedClient { @@ -328,28 +328,16 @@ impl AdminApiClient { } } - async fn parse_response( - &self, - response: reqwest::Response, - ) -> ApiResult { - let status = response.status(); - if status.as_u16() == 204 { - return serde_json::from_value(serde_json::Value::Null) - .map_err(|e| ApiError::Parse(e.to_string())); - } - if !status.is_success() { - let text = response.text().await.map_err(|error| { - ApiError::Network(format!("failed to read error response body: {error}")) - })?; - return Err(ApiError::Http { - status: status.as_u16(), - message: text, - }); - } - let text = response - .text() - .await - .map_err(|e| ApiError::Network(e.to_string()))?; + async fn parse_response(response: reqwest::Response) -> ApiResult { + let response = Self::check_response_status(response).await?; + let text = if response.status() == reqwest::StatusCode::NO_CONTENT { + String::new() + } else { + response + .text() + .await + .map_err(|e| ApiError::Network(e.to_string()))? + }; if text.is_empty() { return serde_json::from_value(serde_json::Value::Null) .map_err(|e| ApiError::Parse(e.to_string())); @@ -418,3 +406,84 @@ impl std::fmt::Display for ApiError { } } } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::{Value, json}; + + fn response(status: u16, body: &'static str) -> reqwest::Response { + axum::http::Response::builder() + .status(status) + .body(body) + .expect("valid response") + .into() + } + + #[tokio::test] + async fn parses_successful_json_and_empty_responses() { + for (status, body, expected) in [ + (200, r#"{"value":1}"#, json!({"value": 1})), + (201, "[1,2]", json!([1, 2])), + (202, "null", Value::Null), + (200, "", Value::Null), + (204, "ignored body", Value::Null), + ] { + let actual: Value = AdminApiClient::parse_response(response(status, body)) + .await + .expect("valid response body"); + assert_eq!(actual, expected, "HTTP {status}: {body}"); + } + } + + #[tokio::test] + async fn empty_responses_preserve_null_deserialization_errors() { + let expected = serde_json::from_value::>(Value::Null) + .expect_err("null is not a list") + .to_string(); + for (status, body) in [(200, ""), (204, "ignored body")] { + let error = AdminApiClient::parse_response::>(response(status, body)) + .await + .expect_err("missing list"); + assert_eq!(error.to_string(), format!("parse error: {expected}")); + } + } + + #[tokio::test] + async fn malformed_json_preserves_deserialization_errors() { + for body in [" ", "{", "not JSON"] { + let expected = serde_json::from_str::(body) + .expect_err("malformed JSON") + .to_string(); + let error = AdminApiClient::parse_response::(response(200, body)) + .await + .expect_err("malformed response"); + assert_eq!(error.to_string(), format!("parse error: {expected}")); + } + } + + #[tokio::test] + async fn void_responses_do_not_parse_successful_bodies() { + for status in [200, 201, 202, 204] { + AdminApiClient::parse_void_response(response(status, "not JSON")) + .await + .expect("successful void response"); + } + } + + #[tokio::test] + async fn typed_and_void_responses_preserve_http_errors() { + for status in [302, 400, 403, 404, 500] { + for body in ["", "plain error", r#"{"code":"FORBIDDEN"}"#] { + let typed = AdminApiClient::parse_response::(response(status, body)) + .await + .map(drop); + let empty = AdminApiClient::parse_void_response(response(status, body)).await; + for result in [typed, empty] { + let error = result.expect_err("unsuccessful response"); + assert_eq!(error.to_string(), format!("HTTP {status}: {body}")); + } + } + } + } +} diff --git a/fluxer_admin/src/api/codes.rs b/fluxer_admin/src/api/codes.rs index bdbb45f16..607560e91 100644 --- a/fluxer_admin/src/api/codes.rs +++ b/fluxer_admin/src/api/codes.rs @@ -13,16 +13,17 @@ impl AdminApiClient { duration_quantity: u32, ) -> ApiResult { let body = generated_types::GenerateGiftCodesRequest { - count: crate::api::generated::nonzero_u32(count, "count").map_err(ApiError::Parse)?, + count: crate::api::generated::nonzero_u32(count, "count") + .map_err(ApiError::Parse)? + .into(), duration_quantity: crate::api::generated::nonzero_u32( duration_quantity, "duration_quantity", ) - .map_err(ApiError::Parse)?, - duration_type: generated_types::GenerateGiftCodesRequestDurationType::try_from( - duration_type, - ) - .map_err(|e| ApiError::Parse(e.to_string()))?, + .map_err(ApiError::Parse)? + .into(), + duration_type: generated_types::GiftCodeDurationTypeSchema::try_from(duration_type) + .map_err(|e| ApiError::Parse(e.to_string()))?, }; let response = self .generated() diff --git a/fluxer_admin/src/api/discovery.rs b/fluxer_admin/src/api/discovery.rs index 23a02dc44..cf2326758 100644 --- a/fluxer_admin/src/api/discovery.rs +++ b/fluxer_admin/src/api/discovery.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{ @@ -16,8 +16,7 @@ impl AdminApiClient { .list_admin_discovery_applications() .await .map_err(|e| self.generated_error(e))?; - response - .into_inner() + Vec::from(response.into_inner()) .into_iter() .map(pending_discovery_application) .collect() @@ -29,8 +28,7 @@ impl AdminApiClient { .list_admin_discovery_listings() .await .map_err(|e| self.generated_error(e))?; - response - .into_inner() + Vec::from(response.into_inner()) .into_iter() .map(listed_guild) .collect() @@ -41,16 +39,13 @@ impl AdminApiClient { guild_id: &str, reason: Option<&str>, ) -> ApiResult { - let guild_id = generated_types::SnowflakeType::from(guild_id.to_owned()); - let body = generated_types::DiscoveryAdminApplicationUpdateRequest::from( - generated_types::ApprovedDiscoveryAdminApplicationUpdateRequest { - reason: reason - .map(generated_types::ApprovedDiscoveryAdminApplicationUpdateRequestReason::try_from) - .transpose() - .map_err(|e| ApiError::Parse(e.to_string()))?, - status: generated_types::ApprovedDiscoveryAdminApplicationUpdateRequestStatus::Approved, - }, - ); + let guild_id = snowflake(guild_id); + let body = generated_types::DiscoveryAdminApplicationUpdateRequest::Approved { + reason: reason + .map(generated_types::DiscoveryReviewReason::try_from) + .transpose() + .map_err(|e| ApiError::Parse(e.to_string()))?, + }; let response = self .generated() .update_admin_discovery_application(&guild_id, &body) @@ -64,18 +59,11 @@ impl AdminApiClient { guild_id: &str, reason: &str, ) -> ApiResult { - let guild_id = generated_types::SnowflakeType::from(guild_id.to_owned()); - let body = generated_types::DiscoveryAdminApplicationUpdateRequest::from( - generated_types::RejectedDiscoveryAdminApplicationUpdateRequest { - reason: - generated_types::RejectedDiscoveryAdminApplicationUpdateRequestReason::try_from( - reason, - ) - .map_err(|e| ApiError::Parse(e.to_string()))?, - status: - generated_types::RejectedDiscoveryAdminApplicationUpdateRequestStatus::Rejected, - }, - ); + let guild_id = snowflake(guild_id); + let body = generated_types::DiscoveryAdminApplicationUpdateRequest::Rejected { + reason: generated_types::DiscoveryRejectionReason::try_from(reason) + .map_err(|e| ApiError::Parse(e.to_string()))?, + }; let response = self .generated() .update_admin_discovery_application(&guild_id, &body) @@ -89,7 +77,7 @@ impl AdminApiClient { guild_id: &str, reason: &str, ) -> ApiResult { - let guild_id = generated_types::SnowflakeType::from(guild_id.to_owned()); + let guild_id = snowflake(guild_id); let body = generated_types::DiscoveryAdminRemoveRequest { reason: generated_types::DiscoveryAdminRemoveRequestReason::try_from(reason) .map_err(|e| ApiError::Parse(e.to_string()))?, diff --git a/fluxer_admin/src/api/generated.rs b/fluxer_admin/src/api/generated.rs index d3fe5853f..58817c5c8 100644 --- a/fluxer_admin/src/api/generated.rs +++ b/fluxer_admin/src/api/generated.rs @@ -16,6 +16,10 @@ pub use inner::types; pub use inner::Client as GeneratedClient; +pub(crate) fn snowflake(value: &str) -> types::SnowflakeType { + types::SnowflakeType::Variant0(value.to_owned()) +} + pub(crate) fn number_to_u64(value: f64, field: &str) -> Result { const MAX_SAFE_INTEGER: f64 = 9_007_199_254_740_991.0; if !value.is_finite() || value < 0.0 || value.fract() != 0.0 || value > MAX_SAFE_INTEGER { @@ -126,10 +130,10 @@ mod tests { let response: SearchGuildsResponse = serde_json::from_value(json).expect("failed to deserialize SearchGuildsResponse"); - assert_eq!(response.total as i64, 1); + assert_eq!(response.total, 1.0); assert_eq!(response.guilds.len(), 1); assert_eq!(response.guilds[0].name, "Test Guild"); - assert_eq!(response.guilds[0].member_count, 42); + assert_eq!(*response.guilds[0].member_count, 42); } #[test] diff --git a/fluxer_admin/src/api/guild_assets.rs b/fluxer_admin/src/api/guild_assets.rs index fb8465676..b10c139b5 100644 --- a/fluxer_admin/src/api/guild_assets.rs +++ b/fluxer_admin/src/api/guild_assets.rs @@ -1,13 +1,13 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::snowflake; use super::client::{AdminApiClient, ApiResult}; use super::types::{ListGuildEmojisResponse, ListGuildStickersResponse}; impl AdminApiClient { pub async fn list_guild_emojis(&self, guild_id: &str) -> ApiResult { - let guild_id = generated_types::SnowflakeType::from(guild_id.to_owned()); + let guild_id = snowflake(guild_id); let response = self .generated() .list_admin_guild_emojis(&guild_id) @@ -20,7 +20,7 @@ impl AdminApiClient { &self, guild_id: &str, ) -> ApiResult { - let guild_id = generated_types::SnowflakeType::from(guild_id.to_owned()); + let guild_id = snowflake(guild_id); let response = self .generated() .list_admin_guild_stickers(&guild_id) diff --git a/fluxer_admin/src/api/guilds.rs b/fluxer_admin/src/api/guilds.rs index 42af60881..e3d659dd5 100644 --- a/fluxer_admin/src/api/guilds.rs +++ b/fluxer_admin/src/api/guilds.rs @@ -1,9 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use serde::Deserialize; use super::client::{AdminApiClient, ApiError, ApiResult}; +use super::reports::SearchReportsParams; use super::types::{ GuildAuditLogResponse, GuildDetailInfo, GuildInfo, GuildUpdateResponse, ListGuildMembersResponse, LookupGuildResponse, SearchGuildsResponse, SearchReportsResponse, @@ -28,13 +29,8 @@ impl AdminApiClient { } pub async fn get_guild_by_id(&self, guild_id: &str) -> ApiResult { - let response = self - .generated() - .get_admin_guild(&snowflake(guild_id)) - .await - .map_err(|e| self.generated_error(e))?; - let resp: LookupGuildResponse = self.generated_value(response.into_inner())?; - resp.guild + self.lookup_guild(guild_id) + .await? .map(GuildInfo::from) .ok_or_else(|| super::client::ApiError::Http { status: 404, @@ -144,8 +140,7 @@ impl AdminApiClient { let limit = limit .map(i32::try_from) .transpose() - .map_err(|e| ApiError::Parse(e.to_string()))? - .map(generated_types::Int32Type::from); + .map_err(|e| ApiError::Parse(e.to_string()))?; let response = self .generated() .list_admin_guild_audit_logs( @@ -153,7 +148,7 @@ impl AdminApiClient { None, None, before.as_ref(), - limit.as_ref(), + limit, None, ) .await @@ -259,37 +254,27 @@ impl AdminApiClient { limit: u32, offset: u32, ) -> ApiResult { - self.search_reports( - None, - None, - None, - None, - None, - None, - Some(guild_id), - None, - None, - None, - None, - None, + self.search_reports(&SearchReportsParams { + reported_guild_id: Some(guild_id), limit, offset, - ) + ..Default::default() + }) .await } } #[derive(Deserialize)] struct GuildSettingsPatch { - content_warning_level: Option, + content_warning_level: Option, content_warning_text: Option, - default_message_notifications: Option, + default_message_notifications: Option, disabled_operations: Option, - explicit_content_filter: Option, - mfa_level: Option, + explicit_content_filter: Option, + mfa_level: Option, nsfw: Option, - nsfw_level: Option, - verification_level: Option, + nsfw_level: Option, + verification_level: Option, } fn search_guilds_response( @@ -317,7 +302,7 @@ fn guild_admin_response(response: generated_types::GuildAdminResponse) -> ApiRes owner_global_name: response.owner_global_name, owner_discriminator: response.owner_discriminator, member_count: crate::api::generated::i64_to_u64( - i64::from(response.member_count), + i64::from(i32::from(response.member_count)), "member_count", ) .map_err(ApiError::Parse)?, @@ -325,7 +310,7 @@ fn guild_admin_response(response: generated_types::GuildAdminResponse) -> ApiRes nsfw_level: response.nsfw_level.map(i32::from), nsfw: response.nsfw, content_warning_level: response.content_warning_level.map(i32::from), - content_warning_text: response.content_warning_text, + content_warning_text: response.content_warning_text.map(String::from), description: None, vanity_url_code: None, }) @@ -338,9 +323,9 @@ fn guild_update_response( Ok(GuildUpdateResponse { guild: GuildInfo { id: String::from(guild.id), - name: guild.name, - icon: guild.icon, - banner: guild.banner, + name: String::from(guild.name), + icon: guild.icon.map(String::from), + banner: guild.banner.map(String::from), owner_id: String::from(guild.owner_id), owner_username: None, owner_global_name: None, @@ -350,11 +335,11 @@ fn guild_update_response( "member_count", ) .map_err(ApiError::Parse)?, - features: guild.features, + features: guild.features.into_iter().map(String::from).collect(), nsfw_level: guild.nsfw_level.map(i32::from), nsfw: guild.nsfw, content_warning_level: guild.content_warning_level.map(i32::from), - content_warning_text: guild.content_warning_text, + content_warning_text: guild.content_warning_text.map(String::from), description: None, vanity_url_code: None, }, @@ -380,10 +365,6 @@ fn guild_settings_request( }) } -fn snowflake(value: &str) -> generated_types::SnowflakeType { - generated_types::SnowflakeType::from(value.to_owned()) -} - fn guild_features(values: &[String]) -> Vec { values .iter() diff --git a/fluxer_admin/src/api/jobs.rs b/fluxer_admin/src/api/jobs.rs index 6f9caf1af..47014790b 100644 --- a/fluxer_admin/src/api/jobs.rs +++ b/fluxer_admin/src/api/jobs.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later +use crate::api::generated::snowflake; + use super::client::{AdminApiClient, ApiResult}; use super::types::{ActiveJobsResponse, CancelJobResponse, GetJobResponse, ListJobsResponse}; @@ -39,7 +41,7 @@ impl AdminApiClient { pub async fn get_job(&self, job_id: &str) -> ApiResult { let response = self .generated() - .get_admin_job(job_id) + .get_admin_job(&snowflake(job_id)) .await .map_err(|e| self.generated_error(e))?; self.generated_value(response.into_inner()) diff --git a/fluxer_admin/src/api/messages.rs b/fluxer_admin/src/api/messages.rs index 8f0d9b2fa..d4ad3cee6 100644 --- a/fluxer_admin/src/api/messages.rs +++ b/fluxer_admin/src/api/messages.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{ @@ -43,7 +43,8 @@ impl AdminApiClient { attachment_id: snowflake(attachment_id), channel_id: snowflake(channel_id), confirmed_viewed: true, - filename: filename.to_owned(), + filename: generated_types::ReportAttachmentToNcmecRequestFilename::try_from(filename) + .map_err(|e| ApiError::Parse(e.to_string()))?, message_id: snowflake(message_id), reporter_full_name: generated_types::ReportAttachmentToNcmecRequestReporterFullName::try_from( @@ -119,7 +120,7 @@ impl AdminApiClient { ) -> ApiResult { let response = self .generated() - .get_admin_message_shred(job_id) + .get_admin_message_shred(&snowflake(job_id)) .await .map_err(|e| self.generated_error(e))?; self.generated_value(response.into_inner()) @@ -133,13 +134,15 @@ impl AdminApiClient { context_limit: u32, ) -> ApiResult { let context_limit = context_limit.to_string(); + let filename = generated_types::SearchAdminMessagesFilename::try_from(filename) + .map_err(|e| ApiError::Parse(e.to_string()))?; let response = self .generated() .search_admin_messages( Some(&snowflake(attachment_id)), &snowflake(channel_id), Some(context_limit.as_str()), - Some(filename), + Some(&filename), None, None, None, @@ -195,7 +198,3 @@ impl AdminApiClient { self.generated_value(response.into_inner()) } } - -fn snowflake(value: &str) -> generated_types::SnowflakeType { - generated_types::SnowflakeType::from(value.to_owned()) -} diff --git a/fluxer_admin/src/api/reports.rs b/fluxer_admin/src/api/reports.rs index 4b107a51d..c98afe57d 100644 --- a/fluxer_admin/src/api/reports.rs +++ b/fluxer_admin/src/api/reports.rs @@ -1,10 +1,30 @@ // SPDX-License-Identifier: AGPL-3.0-or-later +use crate::api::generated::snowflake; + use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{ ListReportsResponse, ReportEntry, ResolveReportResponse, SearchReportsResponse, }; +#[derive(Default)] +pub struct SearchReportsParams<'a> { + pub query: Option<&'a str>, + pub status: Option, + pub report_type: Option, + pub category: Option<&'a str>, + pub reporter_id: Option<&'a str>, + pub reported_user_id: Option<&'a str>, + pub reported_guild_id: Option<&'a str>, + pub reported_channel_id: Option<&'a str>, + pub guild_context_id: Option<&'a str>, + pub resolved_by_admin_id: Option<&'a str>, + pub sort_by: Option<&'a str>, + pub sort_order: Option<&'a str>, + pub limit: u32, + pub offset: u32, +} + impl AdminApiClient { pub async fn list_reports( &self, @@ -26,7 +46,7 @@ impl AdminApiClient { pub async fn get_report(&self, report_id: &str) -> ApiResult { let response = self .generated() - .get_admin_report(report_id) + .get_admin_report(&snowflake(report_id)) .await .map_err(|e| self.generated_error(e))?; self.generated_value(response.into_inner()) @@ -50,51 +70,55 @@ impl AdminApiClient { .await } - #[allow(clippy::too_many_arguments)] pub async fn search_reports( &self, - query: Option<&str>, - status: Option, - report_type: Option, - category: Option<&str>, - reporter_id: Option<&str>, - reported_user_id: Option<&str>, - reported_guild_id: Option<&str>, - reported_channel_id: Option<&str>, - guild_context_id: Option<&str>, - resolved_by_admin_id: Option<&str>, - sort_by: Option<&str>, - sort_order: Option<&str>, - limit: u32, - offset: u32, + params: &SearchReportsParams<'_>, ) -> ApiResult { - let status = status.map(report_status).transpose()?.unwrap_or_default(); - let report_type = report_type + let status = params + .status + .map(report_status) + .transpose()? + .unwrap_or_default(); + let report_type = params + .report_type .map(report_type_name) .transpose()? .unwrap_or_default(); - let sort_by = sort_by.map(report_sort_by).transpose()?.unwrap_or_default(); - let limit = limit.to_string(); - let offset = offset.to_string(); + let sort_by = params + .sort_by + .map(report_sort_by) + .transpose()? + .unwrap_or_default(); + let limit = params.limit.to_string(); + let offset = params.offset.to_string(); let query_params = [ - ("q", query.unwrap_or_default()), + ("q", params.query.unwrap_or_default()), ("status", status), ("report_type", report_type), - ("category", category.unwrap_or_default()), - ("reporter_id", reporter_id.unwrap_or_default()), - ("reported_user_id", reported_user_id.unwrap_or_default()), - ("reported_guild_id", reported_guild_id.unwrap_or_default()), + ("category", params.category.unwrap_or_default()), + ("reporter_id", params.reporter_id.unwrap_or_default()), + ( + "reported_user_id", + params.reported_user_id.unwrap_or_default(), + ), + ( + "reported_guild_id", + params.reported_guild_id.unwrap_or_default(), + ), ( "reported_channel_id", - reported_channel_id.unwrap_or_default(), + params.reported_channel_id.unwrap_or_default(), + ), + ( + "guild_context_id", + params.guild_context_id.unwrap_or_default(), ), - ("guild_context_id", guild_context_id.unwrap_or_default()), ( "resolved_by_admin_id", - resolved_by_admin_id.unwrap_or_default(), + params.resolved_by_admin_id.unwrap_or_default(), ), ("sort_by", sort_by), - ("sort_order", sort_order.unwrap_or_default()), + ("sort_order", params.sort_order.unwrap_or_default()), ("limit", limit.as_str()), ("offset", offset.as_str()), ]; @@ -107,22 +131,12 @@ impl AdminApiClient { limit: u32, offset: u32, ) -> ApiResult { - self.search_reports( - None, - None, - None, - None, - Some(reporter_id), - None, - None, - None, - None, - None, - None, - None, + self.search_reports(&SearchReportsParams { + reporter_id: Some(reporter_id), limit, offset, - ) + ..Default::default() + }) .await } @@ -132,22 +146,12 @@ impl AdminApiClient { limit: u32, offset: u32, ) -> ApiResult { - self.search_reports( - None, - None, - None, - None, - None, - Some(reported_user_id), - None, - None, - None, - None, - None, - None, + self.search_reports(&SearchReportsParams { + reported_user_id: Some(reported_user_id), limit, offset, - ) + ..Default::default() + }) .await } } @@ -179,3 +183,61 @@ fn report_sort_by(value: &str) -> ApiResult<&'static str> { ))), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn report_statuses_preserve_the_closed_wire_mapping() { + for (value, expected) in [(0, "pending"), (1, "resolved")] { + assert_eq!(report_status(value).expect("supported status"), expected); + } + for value in [-1, 2] { + assert_eq!( + report_status(value) + .expect_err("unknown status") + .to_string(), + format!("parse error: unknown report status: {value}") + ); + } + } + + #[test] + fn report_types_preserve_the_closed_wire_mapping() { + for (value, expected) in [(0, "message"), (1, "user"), (2, "guild")] { + assert_eq!(report_type_name(value).expect("supported type"), expected); + } + for value in [-1, 3] { + assert_eq!( + report_type_name(value) + .expect_err("unknown type") + .to_string(), + format!("parse error: unknown report type: {value}") + ); + } + } + + #[test] + fn report_sort_fields_accept_only_the_existing_aliases() { + for (field, expected) in [ + ("createdAt", "created_at"), + ("created_at", "created_at"), + ("reportedAt", "reported_at"), + ("reported_at", "reported_at"), + ("resolvedAt", "resolved_at"), + ("resolved_at", "resolved_at"), + ] { + assert_eq!( + report_sort_by(field).expect("supported sort field"), + expected + ); + } + assert_eq!( + report_sort_by("unknown") + .expect_err("unknown sort field") + .to_string(), + "parse error: unknown report sort field: unknown" + ); + } +} diff --git a/fluxer_admin/src/api/search.rs b/fluxer_admin/src/api/search.rs index 0bc376b41..24f95fea8 100644 --- a/fluxer_admin/src/api/search.rs +++ b/fluxer_admin/src/api/search.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{IndexRefreshStatusResponse, RefreshSearchIndexResponse}; @@ -11,8 +11,11 @@ impl AdminApiClient { index_type: &str, guild_id: Option<&str>, ) -> ApiResult { + let index_type = + generated_types::CreateAdminSearchIndexRefreshIndexName::try_from(index_type) + .map_err(|e| ApiError::Parse(e.to_string()))?; let body = generated_types::RefreshSearchIndexRequest { - guild_id: guild_id.map(|id| generated_types::SnowflakeType::from(id.to_owned())), + guild_id: guild_id.map(snowflake), user_id: None, }; let response = self diff --git a/fluxer_admin/src/api/system.rs b/fluxer_admin/src/api/system.rs index fff1f0ac5..a00a9b3fe 100644 --- a/fluxer_admin/src/api/system.rs +++ b/fluxer_admin/src/api/system.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiResult}; use super::types::{ @@ -24,11 +24,7 @@ impl AdminApiClient { guild_ids: &[String], ) -> ApiResult { let body = generated_types::ReloadGuildsRequest { - guild_ids: guild_ids - .iter() - .cloned() - .map(generated_types::SnowflakeType::from) - .collect(), + guild_ids: guild_ids.iter().map(|id| snowflake(id)).collect(), }; let response = self .generated() diff --git a/fluxer_admin/src/api/system_dm.rs b/fluxer_admin/src/api/system_dm.rs index 204a79e5e..7e82d2ba7 100644 --- a/fluxer_admin/src/api/system_dm.rs +++ b/fluxer_admin/src/api/system_dm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::SendSystemDmResponse; @@ -14,11 +14,7 @@ impl AdminApiClient { let body = generated_types::SendSystemDmRequest { content: generated_types::SendSystemDmRequestContent::try_from(content) .map_err(|e| ApiError::Parse(e.to_string()))?, - user_ids: user_ids - .iter() - .cloned() - .map(generated_types::SnowflakeType::from) - .collect(), + user_ids: user_ids.iter().map(|id| snowflake(id)).collect(), }; let response = self .generated() diff --git a/fluxer_admin/src/api/types/instance_config.rs b/fluxer_admin/src/api/types/instance_config.rs index 126a7b98d..d60227fba 100644 --- a/fluxer_admin/src/api/types/instance_config.rs +++ b/fluxer_admin/src/api/types/instance_config.rs @@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize}; +pub use crate::api::generated::types::VoiceNoiseSuppressionBackendSchema as NoiseSuppressionBackend; + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct InstanceConfigResponse { pub sso: SsoConfigResponse, @@ -443,19 +445,6 @@ impl VoiceE2eeScope { pub const VOICE_NS_MAX_TARGETED_USERS: usize = 1_000; pub const VOICE_NS_MAX_GUILD_OVERRIDES: usize = 200; -#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] -#[serde(rename_all = "snake_case")] -pub enum NoiseSuppressionBackend { - None, - #[default] - Standard, - Gate, - Speex, - Rnnoise, - Gtcrn, - DeepFilter, -} - impl NoiseSuppressionBackend { pub const ALL: [Self; 7] = [ Self::None, @@ -467,18 +456,6 @@ impl NoiseSuppressionBackend { Self::DeepFilter, ]; - pub fn as_str(&self) -> &'static str { - match self { - Self::None => "none", - Self::Standard => "standard", - Self::Gate => "gate", - Self::Speex => "speex", - Self::Rnnoise => "rnnoise", - Self::Gtcrn => "gtcrn", - Self::DeepFilter => "deep_filter", - } - } - pub fn label(&self) -> &'static str { match self { Self::None => "None (pass-through)", @@ -490,12 +467,6 @@ impl NoiseSuppressionBackend { Self::DeepFilter => "DeepFilterNet", } } - - pub fn from_value(value: &str) -> Option { - Self::ALL - .into_iter() - .find(|backend| backend.as_str() == value) - } } #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -505,30 +476,19 @@ pub struct VoiceNoiseSuppressionGuildOverride { } #[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(default)] pub struct VoiceNoiseSuppressionConfigResponse { - #[serde(default)] pub enabled: bool, - #[serde(default)] pub config_version: u64, - #[serde(default)] pub default_backend: NoiseSuppressionBackend, - #[serde(default = "default_voice_noise_suppression_enabled_backends")] pub enabled_backends: Vec, - #[serde(default = "default_voice_noise_suppression_allow_user_override")] pub allow_user_override: bool, - #[serde(default)] pub rollout_basis_points: u32, - #[serde(default = "default_voice_noise_suppression_rollout_salt")] pub rollout_salt: String, - #[serde(default)] pub included_user_ids: Vec, - #[serde(default)] pub excluded_user_ids: Vec, - #[serde(default)] pub guild_overrides: Vec, - #[serde(default)] pub stereo_enabled: bool, - #[serde(default = "default_voice_noise_suppression_strength")] pub suppression_strength: u32, } @@ -538,35 +498,19 @@ impl Default for VoiceNoiseSuppressionConfigResponse { enabled: false, config_version: 0, default_backend: NoiseSuppressionBackend::Standard, - enabled_backends: default_voice_noise_suppression_enabled_backends(), - allow_user_override: default_voice_noise_suppression_allow_user_override(), + enabled_backends: NoiseSuppressionBackend::ALL.to_vec(), + allow_user_override: true, rollout_basis_points: 0, - rollout_salt: default_voice_noise_suppression_rollout_salt(), + rollout_salt: "voice-ns-v1".to_owned(), included_user_ids: Vec::new(), excluded_user_ids: Vec::new(), guild_overrides: Vec::new(), stereo_enabled: false, - suppression_strength: default_voice_noise_suppression_strength(), + suppression_strength: 80, } } } -fn default_voice_noise_suppression_enabled_backends() -> Vec { - NoiseSuppressionBackend::ALL.to_vec() -} - -fn default_voice_noise_suppression_allow_user_override() -> bool { - true -} - -fn default_voice_noise_suppression_rollout_salt() -> String { - "voice-ns-v1".to_owned() -} - -fn default_voice_noise_suppression_strength() -> u32 { - 80 -} - #[derive(Clone, Debug, Default, Serialize)] pub struct VoiceNoiseSuppressionConfigUpdateRequest { #[serde(skip_serializing_if = "Option::is_none")] @@ -594,30 +538,21 @@ pub struct VoiceNoiseSuppressionConfigUpdateRequest { } #[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(default)] pub struct ExperimentDeliveryConfigResponse { - #[serde(default = "default_experiment_poll_interval_seconds")] pub poll_interval_seconds: u64, - #[serde(default = "default_experiment_poll_jitter_percent")] pub poll_jitter_percent: u32, } impl Default for ExperimentDeliveryConfigResponse { fn default() -> Self { Self { - poll_interval_seconds: default_experiment_poll_interval_seconds(), - poll_jitter_percent: default_experiment_poll_jitter_percent(), + poll_interval_seconds: 300, + poll_jitter_percent: 15, } } } -fn default_experiment_poll_interval_seconds() -> u64 { - 300 -} - -fn default_experiment_poll_jitter_percent() -> u32 { - 15 -} - #[derive(Clone, Debug, Default, Serialize)] pub struct ExperimentDeliveryConfigUpdateRequest { #[serde(skip_serializing_if = "Option::is_none")] @@ -1024,31 +959,14 @@ pub struct CreateRegistrationUrlResponse { #[cfg(test)] mod tests { use super::*; - - const VOICE_NOISE_SUPPRESSION_SCHEMA: &str = include_str!( - "../../../../packages/schema/src/domains/admin/VoiceNoiseSuppressionSchemas.ts" - ); - - fn schema_backend_ids() -> Vec { - let (_, rest) = VOICE_NOISE_SUPPRESSION_SCHEMA - .split_once("export const VOICE_NOISE_SUPPRESSION_BACKENDS = [") - .expect("backend list start"); - let (block, _) = rest.split_once(']').expect("backend list end"); - block - .split(',') - .map(|entry| entry.trim().trim_matches('\'').to_owned()) - .filter(|entry| !entry.is_empty()) - .collect() - } + use crate::api::generated::types as generated_types; + use serde_json::json; #[test] - fn noise_suppression_backend_ids_are_the_documented_list() { + fn noise_suppression_backend_choices_use_the_generated_wire_contract() { assert_eq!( - NoiseSuppressionBackend::ALL - .iter() - .map(NoiseSuppressionBackend::as_str) - .collect::>(), - vec![ + serde_json::to_value(NoiseSuppressionBackend::ALL).expect("serializable backends"), + json!([ "none", "standard", "gate", @@ -1056,29 +974,70 @@ mod tests { "rnnoise", "gtcrn", "deep_filter" - ] + ]) ); + assert!(serde_json::from_value::(json!("deepfilter")).is_err()); } #[test] - fn noise_suppression_backend_ids_match_the_schema_contract() { + fn default_instance_experiment_config_matches_the_published_contract() { + let schema: serde_json::Value = + serde_json::from_str(include_str!("../../../openapi-admin.json")) + .expect("admin schema"); + let noise = serde_json::from_value::(json!({})) + .expect("default noise config"); + let delivery = serde_json::from_value::(json!({})) + .expect("default delivery config"); + let noise = serde_json::to_value(noise).expect("serializable noise config"); + let delivery = serde_json::to_value(delivery).expect("serializable delivery config"); + let generated_noise: generated_types::VoiceNoiseSuppressionConfigResponse = + serde_json::from_value(noise.clone()).expect("generated noise config contract"); + let generated_delivery: generated_types::ExperimentDeliveryConfigResponse = + serde_json::from_value(delivery.clone()).expect("generated delivery config contract"); assert_eq!( - NoiseSuppressionBackend::ALL - .iter() - .map(|backend| backend.as_str().to_owned()) - .collect::>(), - schema_backend_ids() + serde_json::to_value(generated_noise).expect("serializable generated noise config"), + noise ); + assert_eq!( + serde_json::to_value(generated_delivery) + .expect("serializable generated delivery config"), + delivery + ); + for (name, value) in [ + ("VoiceNoiseSuppressionConfigResponse", noise), + ("ExperimentDeliveryConfigResponse", delivery), + ] { + for (field, value) in value.as_object().expect("config object") { + assert_eq!( + value, &schema["components"]["schemas"][name]["properties"][field]["default"], + "{name}.{field}" + ); + } + } } #[test] - fn noise_suppression_backend_round_trips_every_id() { - for backend in NoiseSuppressionBackend::ALL { - assert_eq!( - NoiseSuppressionBackend::from_value(backend.as_str()), - Some(backend) - ); - } - assert_eq!(NoiseSuppressionBackend::from_value("deepfilter"), None); + fn noise_suppression_update_preserves_empty_lists_and_omitted_fields() { + let update = VoiceNoiseSuppressionConfigUpdateRequest { + enabled_backends: Some(Vec::new()), + included_user_ids: Some(Vec::new()), + excluded_user_ids: Some(Vec::new()), + guild_overrides: Some(Vec::new()), + ..Default::default() + }; + let value = serde_json::to_value(update).expect("serializable update"); + serde_json::from_value::( + value.clone(), + ) + .expect("generated update contract"); + assert_eq!( + value, + json!({"enabled_backends": [], "included_user_ids": [], "excluded_user_ids": [], "guild_overrides": []}) + ); + assert_eq!( + serde_json::to_value(VoiceNoiseSuppressionConfigUpdateRequest::default()) + .expect("serializable update"), + json!({}) + ); } } diff --git a/fluxer_admin/src/api/users.rs b/fluxer_admin/src/api/users.rs index 44ec778dc..bf2e0f882 100644 --- a/fluxer_admin/src/api/users.rs +++ b/fluxer_admin/src/api/users.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -use crate::api::generated::types as generated_types; +use crate::api::generated::{snowflake, types as generated_types}; use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{ @@ -362,11 +362,8 @@ impl AdminApiClient { ) -> ApiResult { let body = generated_types::AdminUserUsernameUpdateRequest { discriminator: discriminator - .map(generated_types::DiscriminatorType::try_from) - .transpose() - .map_err(|e| ApiError::Parse(e.to_string()))?, - username: generated_types::UsernameType::try_from(username) - .map_err(|e| ApiError::Parse(e.to_string()))?, + .map(|value| generated_types::DiscriminatorType::String(value.to_owned())), + username: generated_types::UsernameType::from(username.to_owned()), }; let response = self .generated() @@ -399,7 +396,8 @@ impl AdminApiClient { ) -> ApiResult { let body = generated_types::AdminUserBanRequest { duration_hours: i32::try_from(duration_hours) - .map_err(|e| ApiError::Parse(e.to_string()))?, + .map_err(|e| ApiError::Parse(e.to_string()))? + .into(), reason: reason.map(std::borrow::ToOwned::to_owned), }; let resp: UserMutationResponse = self @@ -430,10 +428,12 @@ impl AdminApiClient { days_until_deletion: u32, ) -> ApiResult { let body = generated_types::AdminUserDeletionScheduleRequest { - days_until_deletion: Some( - crate::api::generated::nonzero_u32(days_until_deletion, "days_until_deletion") - .map_err(ApiError::Parse)?, - ), + days_until_deletion: crate::api::generated::nonzero_u32( + days_until_deletion, + "days_until_deletion", + ) + .map_err(ApiError::Parse)? + .into(), public_reason: public_reason.map(std::borrow::ToOwned::to_owned), reason_code: crate::api::generated::deletion_reason_code(reason_code, "reason_code") .map_err(ApiError::Parse)?, @@ -484,10 +484,10 @@ impl AdminApiClient { target_id: &str, category: &str, ) -> ApiResult<()> { - let category = generated_types::RemoveAdminUserRelationshipCategory::try_from(category) + let category = generated_types::RelationshipCategoryEnum::try_from(category) .map_err(|e| ApiError::Parse(e.to_string()))?; self.generated() - .remove_admin_user_relationship(&snowflake(user_id), target_id, category) + .remove_admin_user_relationship(&snowflake(user_id), &snowflake(target_id), category) .await .map_err(|e| self.generated_error(e))?; Ok(()) @@ -498,7 +498,7 @@ impl AdminApiClient { user_id: &str, category: &str, ) -> ApiResult { - let category = generated_types::ClearAdminUserRelationshipsCategory::try_from(category) + let category = generated_types::RelationshipCategoryEnum::try_from(category) .map_err(|e| ApiError::Parse(e.to_string()))?; let response = self .generated() @@ -565,10 +565,6 @@ fn bool_param(value: bool) -> &'static str { if value { "true" } else { "false" } } -fn snowflake(value: &str) -> generated_types::SnowflakeType { - generated_types::SnowflakeType::from(value.to_owned()) -} - fn user_flags(values: &[String]) -> Vec { values .iter() diff --git a/fluxer_admin/src/api/voice.rs b/fluxer_admin/src/api/voice.rs index 154a35207..76d06c1a1 100644 --- a/fluxer_admin/src/api/voice.rs +++ b/fluxer_admin/src/api/voice.rs @@ -55,10 +55,11 @@ impl AdminApiClient { params: &serde_json::Value, ) -> ApiResult { let region_id = required_field(params, "id")?; - validate_against::(params)?; + let body = voice_request_body(params, &["id"])?; + validate_against::(&body)?; self.patch_with_reason( &format!("/admin/voice/regions/{}", urlencoding::encode(®ion_id)), - Some(params), + Some(&body), None, ) .await @@ -101,9 +102,10 @@ impl AdminApiClient { ) -> ApiResult { let region_id = required_field(params, "region_id")?; paired_coordinates(params)?; - let body = - serde_json::from_value::(params.clone()) - .map_err(|e| ApiError::Parse(e.to_string()))?; + let body = serde_json::from_value::( + voice_request_body(params, &["region_id"])?, + ) + .map_err(|e| ApiError::Parse(e.to_string()))?; let response = self .generated() .create_admin_voice_server(®ion_id, &body) @@ -119,14 +121,15 @@ impl AdminApiClient { let region_id = required_field(params, "region_id")?; let server_id = required_field(params, "server_id")?; paired_coordinates(params)?; - validate_against::(params)?; + let body = voice_request_body(params, &["region_id", "server_id"])?; + validate_against::(&body)?; self.patch_with_reason( &format!( "/admin/voice/regions/{}/servers/{}", urlencoding::encode(®ion_id), urlencoding::encode(&server_id) ), - Some(params), + Some(&body), None, ) .await @@ -156,6 +159,20 @@ fn validate_against(params: &serde_json::Value) .map_err(|e| ApiError::Parse(e.to_string())) } +fn voice_request_body( + params: &serde_json::Value, + path_fields: &[&str], +) -> ApiResult { + let mut body = params + .as_object() + .ok_or_else(|| ApiError::Parse("voice request body must be an object".to_owned()))? + .clone(); + for field in path_fields { + body.remove(*field); + } + Ok(body.into()) +} + fn paired_coordinates(params: &serde_json::Value) -> ApiResult<()> { let has_coordinate = |field: &str| params.get(field).is_some_and(|value| !value.is_null()); if has_coordinate("latitude") == has_coordinate("longitude") { @@ -174,3 +191,67 @@ fn required_field(params: &serde_json::Value, field: &str) -> ApiResult .map(std::borrow::ToOwned::to_owned) .ok_or_else(|| ApiError::Parse(format!("{field} is required"))) } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn region_update_body_preserves_explicit_restriction_clears() { + let expected = json!({ + "required_guild_features": [], + "allowed_guild_ids": [], + "allowed_user_ids": [], + }); + let mut params = expected.clone(); + params["id"] = json!("eu"); + let body = voice_request_body(¶ms, &["id"]).expect("region body"); + validate_against::(&body) + .expect("valid region body"); + assert_eq!(body, expected); + } + + #[test] + fn server_update_body_preserves_clears_and_omitted_restrictions() { + for expected in [ + json!({ + "required_guild_features": [], + "allowed_guild_ids": [], + "allowed_user_ids": [], + "soft_connection_limit": null, + "latitude": null, + "longitude": null, + }), + json!({"is_active": false}), + ] { + let mut params = expected.clone(); + params["region_id"] = json!("eu"); + params["server_id"] = json!("primary"); + let body = + voice_request_body(¶ms, &["region_id", "server_id"]).expect("server body"); + validate_against::(&body) + .expect("valid server body"); + assert_eq!(body, expected); + } + } + + #[test] + fn create_server_body_keeps_the_server_id_and_rejects_missing_fields() { + let expected = json!({ + "server_id": "primary", + "endpoint": "wss://voice.example.com", + "api_key": "key", + "api_secret": "secret", + }); + let mut params = expected.clone(); + params["region_id"] = json!("eu"); + let body = voice_request_body(¶ms, &["region_id"]).expect("server body"); + validate_against::(&body) + .expect("valid server body"); + assert_eq!(body, expected); + assert!( + validate_against::(&json!({})).is_err() + ); + } +} diff --git a/fluxer_admin/src/routes/reports.rs b/fluxer_admin/src/routes/reports.rs index cb3dd89f0..6770cab2a 100644 --- a/fluxer_admin/src/routes/reports.rs +++ b/fluxer_admin/src/routes/reports.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use crate::{ - api::client::{AdminApiClient, ApiResultExt}, + api::{ + client::{AdminApiClient, ApiResultExt}, + reports::SearchReportsParams, + }, config::AdminConfig, middleware::{ auth::AuthContext, @@ -89,22 +92,22 @@ async fn reports_list( .as_deref() .and_then(|s| s.parse::().ok()); let reports = client - .search_reports( - search_query.as_deref(), + .search_reports(&SearchReportsParams { + query: search_query.as_deref(), status, report_type, - query.category.as_deref(), - query.reporter_id.as_deref(), - query.reported_user_id.as_deref(), - query.reported_guild_id.as_deref(), - query.reported_channel_id.as_deref(), - query.guild_context_id.as_deref(), - query.resolved_by_admin_id.as_deref(), - Some(sort_by), - Some(sort_order), + category: query.category.as_deref(), + reporter_id: query.reporter_id.as_deref(), + reported_user_id: query.reported_user_id.as_deref(), + reported_guild_id: query.reported_guild_id.as_deref(), + reported_channel_id: query.reported_channel_id.as_deref(), + guild_context_id: query.guild_context_id.as_deref(), + resolved_by_admin_id: query.resolved_by_admin_id.as_deref(), + sort_by: Some(sort_by), + sort_order: Some(sort_order), limit, offset, - ) + }) .await .log_error("search reports"); diff --git a/fluxer_admin/src/routes/system_actions.rs b/fluxer_admin/src/routes/system_actions.rs index 4e25ffa3c..047f561ee 100644 --- a/fluxer_admin/src/routes/system_actions.rs +++ b/fluxer_admin/src/routes/system_actions.rs @@ -203,14 +203,14 @@ pub async fn instance_config_post( let update = build_media_update(&form); instance_config_result(client.update_instance_config(&update).await) } - "update_voice_noise_suppression" => { - let update = build_voice_noise_suppression_update(&form); - instance_config_result(client.update_instance_config(&update).await) - } - "update_experiment_delivery" => { - let update = build_experiment_delivery_update(&form); - instance_config_result(client.update_instance_config(&update).await) - } + "update_voice_noise_suppression" => match build_voice_noise_suppression_update(&form) { + Ok(update) => instance_config_result(client.update_instance_config(&update).await), + Err(message) => FlashData::error(message), + }, + "update_experiment_delivery" => match build_experiment_delivery_update(&form) { + Ok(update) => instance_config_result(client.update_instance_config(&update).await), + Err(message) => FlashData::error(message), + }, "test_smtp" => match build_smtp_test_request(&form) { Ok(request) => match client.test_instance_smtp_config(&request).await { Ok(response) if response.ok => FlashData::success("SMTP connection verified"), @@ -412,14 +412,7 @@ fn build_sso_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { allowed_domains: Some(allowed), redirect_uri: None, }), - gateway_rollout: None, - registration: None, - app_public: None, - policy: None, - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } @@ -450,14 +443,7 @@ fn build_gateway_rollout_update(form: &MultiValueForm) -> InstanceConfigUpdateRe .parse_u64("gateway_rollout_max_concurrent_guild_starts"), voice_e2ee_scope, }), - sso: None, - registration: None, - app_public: None, - policy: None, - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } @@ -467,36 +453,42 @@ const VOICE_NS_MAX_ROLLOUT_SALT_CHARS: usize = 64; const VOICE_NS_MAX_SNOWFLAKE_LENGTH: usize = 20; const EXPERIMENT_MIN_POLL_INTERVAL_SECONDS: u64 = 60; const EXPERIMENT_MAX_POLL_INTERVAL_SECONDS: u64 = 86_400; -const EXPERIMENT_DEFAULT_POLL_INTERVAL_SECONDS: u64 = 300; const EXPERIMENT_MAX_POLL_JITTER_PERCENT: u32 = 50; -const EXPERIMENT_DEFAULT_POLL_JITTER_PERCENT: u32 = 15; -fn parse_clamped_form_number( +fn parse_form_number( form: &MultiValueForm, key: &str, - empty_value: T, + label: &str, min: T, max: T, -) -> Option +) -> Result, String> where - T: std::str::FromStr + Ord, + T: std::str::FromStr + Ord + std::fmt::Display, { - let raw = form.first(key)?.trim(); - let value = if raw.is_empty() { - empty_value - } else { - raw.parse::().unwrap_or(empty_value) + let Some(raw) = form.first(key) else { + return Ok(None); }; - Some(value.clamp(min, max)) + let invalid = || format!("{label} must be a whole number between {min} and {max}"); + let value = raw.trim().parse::().map_err(|_| invalid())?; + if value < min || value > max { + return Err(invalid()); + } + Ok(Some(value)) } -fn parse_voice_noise_suppression_rollout_salt(form: &MultiValueForm) -> Option { - let salt: String = form - .clean("voice_ns_rollout_salt")? - .chars() - .take(VOICE_NS_MAX_ROLLOUT_SALT_CHARS) - .collect(); - clean_string(&salt) +fn parse_voice_noise_suppression_rollout_salt( + form: &MultiValueForm, +) -> Result, String> { + let Some(raw) = form.first("voice_ns_rollout_salt") else { + return Ok(None); + }; + let salt = raw.trim(); + if salt.is_empty() || salt.encode_utf16().count() > VOICE_NS_MAX_ROLLOUT_SALT_CHARS { + return Err(format!( + "Rollout salt must be between 1 and {VOICE_NS_MAX_ROLLOUT_SALT_CHARS} characters" + )); + } + Ok(Some(salt.to_owned())) } fn is_voice_noise_suppression_snowflake(value: &str) -> bool { @@ -505,135 +497,160 @@ fn is_voice_noise_suppression_snowflake(value: &str) -> bool { && value.bytes().all(|byte| byte.is_ascii_digit()) } -fn parse_voice_noise_suppression_user_ids(value: &str) -> Vec { +fn parse_voice_noise_suppression_user_ids(value: &str, label: &str) -> Result, String> { let mut ids: Vec = Vec::new(); - for candidate in value.split([',', '\n', '\r']) { + for (index, candidate) in value.split([',', '\n', '\r']).enumerate() { let candidate = candidate.trim(); - if !is_voice_noise_suppression_snowflake(candidate) { + if candidate.is_empty() { continue; } + if !is_voice_noise_suppression_snowflake(candidate) { + return Err(format!( + "{label} entry {} must contain 1 to 20 decimal digits", + index + 1 + )); + } if ids.iter().any(|existing| existing == candidate) { continue; } - ids.push(candidate.to_owned()); if ids.len() == VOICE_NS_MAX_TARGETED_USERS { - break; + return Err(format!( + "{label} must contain at most {VOICE_NS_MAX_TARGETED_USERS} unique IDs" + )); } + ids.push(candidate.to_owned()); } - ids + Ok(ids) } fn parse_voice_noise_suppression_guild_overrides( value: &str, -) -> Vec { +) -> Result, String> { let mut overrides: Vec = Vec::new(); - for line in value.lines() { - let Some((guild_id, backend)) = line.split_once('=') else { + for (index, line) in value.lines().enumerate() { + if line.trim().is_empty() { continue; - }; + } + let line_number = index + 1; + let (guild_id, backend) = line.split_once('=').ok_or_else(|| { + format!("Guild overrides line {line_number} must use guild_id=backend") + })?; let guild_id = guild_id.trim(); if !is_voice_noise_suppression_snowflake(guild_id) { - continue; + return Err(format!( + "Guild overrides line {line_number} must use a guild ID with 1 to 20 decimal digits" + )); } - if overrides + let backend = backend.trim().parse().map_err(|_| { + format!("Guild overrides line {line_number} must name a supported backend") + })?; + if let Some(existing) = overrides .iter() - .any(|existing| existing.guild_id == guild_id) + .find(|existing| existing.guild_id == guild_id) { + if existing.backend != backend { + return Err(format!( + "Guild overrides line {line_number} conflicts with an earlier rule for guild {guild_id}" + )); + } continue; } - let Some(backend) = NoiseSuppressionBackend::from_value(backend.trim()) else { - continue; - }; + if overrides.len() == VOICE_NS_MAX_GUILD_OVERRIDES { + return Err(format!( + "Guild overrides must contain at most {VOICE_NS_MAX_GUILD_OVERRIDES} unique guilds" + )); + } overrides.push(VoiceNoiseSuppressionGuildOverride { guild_id: guild_id.to_owned(), backend, }); - if overrides.len() == VOICE_NS_MAX_GUILD_OVERRIDES { - break; - } } - overrides + Ok(overrides) } -fn build_voice_noise_suppression_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { - let selected = - form.list_values_any(&["voice_ns_enabled_backends[]", "voice_ns_enabled_backends"]); +fn build_voice_noise_suppression_update( + form: &MultiValueForm, +) -> Result { + let selected: Vec = form + .list_values_any(&["voice_ns_enabled_backends[]", "voice_ns_enabled_backends"]) + .into_iter() + .map(|value| { + value.parse().map_err(|_| { + "Enabled backends must name supported noise suppression backends".to_owned() + }) + }) + .collect::>()?; let enabled_backends = NoiseSuppressionBackend::ALL .into_iter() - .filter(|backend| selected.iter().any(|value| value == backend.as_str())) + .filter(|backend| selected.contains(backend)) .collect(); - InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, - app_public: None, - policy: None, - integrations: None, - media: None, + Ok(InstanceConfigUpdateRequest { voice_noise_suppression: Some(VoiceNoiseSuppressionConfigUpdateRequest { enabled: Some(form.bool_value("voice_ns_enabled")), default_backend: form .first("voice_ns_default_backend") - .and_then(NoiseSuppressionBackend::from_value), + .map(|value| { + value.parse().map_err(|_| { + "Default backend must name a supported noise suppression backend".to_owned() + }) + }) + .transpose()?, enabled_backends: Some(enabled_backends), allow_user_override: Some(form.bool_value("voice_ns_allow_user_override")), - rollout_basis_points: parse_clamped_form_number( + rollout_basis_points: parse_form_number( form, "voice_ns_rollout_basis_points", - 0, + "Rollout basis points", 0, VOICE_NS_ROLLOUT_BASIS_POINTS_MAX, - ), - rollout_salt: parse_voice_noise_suppression_rollout_salt(form), + )?, + rollout_salt: parse_voice_noise_suppression_rollout_salt(form)?, included_user_ids: Some(parse_voice_noise_suppression_user_ids( form.first("voice_ns_included_user_ids").unwrap_or_default(), - )), + "Included user IDs", + )?), excluded_user_ids: Some(parse_voice_noise_suppression_user_ids( form.first("voice_ns_excluded_user_ids").unwrap_or_default(), - )), + "Excluded user IDs", + )?), guild_overrides: Some(parse_voice_noise_suppression_guild_overrides( form.first("voice_ns_guild_overrides").unwrap_or_default(), - )), + )?), stereo_enabled: Some(form.bool_value("voice_ns_stereo_enabled")), - suppression_strength: parse_clamped_form_number( + suppression_strength: parse_form_number( form, "voice_ns_suppression_strength", - 0, + "Suppression strength", 0, VOICE_NS_SUPPRESSION_STRENGTH_MAX, - ), + )?, }), - experiment_delivery: None, - } + ..Default::default() + }) } -fn build_experiment_delivery_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { - InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, - app_public: None, - policy: None, - integrations: None, - media: None, - voice_noise_suppression: None, +fn build_experiment_delivery_update( + form: &MultiValueForm, +) -> Result { + Ok(InstanceConfigUpdateRequest { experiment_delivery: Some(ExperimentDeliveryConfigUpdateRequest { - poll_interval_seconds: parse_clamped_form_number( + poll_interval_seconds: parse_form_number( form, "experiment_delivery_poll_interval_seconds", - EXPERIMENT_DEFAULT_POLL_INTERVAL_SECONDS, + "Poll interval", EXPERIMENT_MIN_POLL_INTERVAL_SECONDS, EXPERIMENT_MAX_POLL_INTERVAL_SECONDS, - ), - poll_jitter_percent: parse_clamped_form_number( + )?, + poll_jitter_percent: parse_form_number( form, "experiment_delivery_poll_jitter_percent", - EXPERIMENT_DEFAULT_POLL_JITTER_PERCENT, + "Poll jitter", 0, EXPERIMENT_MAX_POLL_JITTER_PERCENT, - ), + )?, }), - } + ..Default::default() + }) } fn build_registration_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { @@ -644,29 +661,19 @@ fn build_registration_update(form: &MultiValueForm) -> InstanceConfigUpdateReque _ => None, }; InstanceConfigUpdateRequest { - gateway_rollout: None, registration: Some(InstanceRegistrationConfigUpdateRequest { mode, admin_registration_urls_enabled: Some( form.bool_value("admin_registration_urls_enabled"), ), }), - sso: None, - app_public: None, - policy: None, - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } fn build_app_public_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { let optional = |key: &str| Some(form.clean(key)); InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, app_public: Some(AppPublicConfigUpdateRequest { branding: Some(AppBrandingConfigUpdateRequest { product_name: form.clean("app_product_name"), @@ -683,20 +690,13 @@ fn build_app_public_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest legal: None, registration: None, }), - policy: None, - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } fn build_app_legal_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { let optional = |key: &str| Some(form.clean(key)); InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, app_public: Some(AppPublicConfigUpdateRequest { branding: None, setup: None, @@ -706,19 +706,12 @@ fn build_app_legal_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest }), registration: None, }), - policy: None, - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } fn build_app_registration_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, app_public: Some(AppPublicConfigUpdateRequest { branding: None, setup: None, @@ -727,11 +720,7 @@ fn build_app_registration_update(form: &MultiValueForm) -> InstanceConfigUpdateR collect_date_of_birth: Some(form.bool_value("app_collect_date_of_birth")), }), }), - policy: None, - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } @@ -747,10 +736,6 @@ fn build_policy_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { let services = build_services_update(form); let deferred_phone_gate = build_deferred_phone_gate_update(form); InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, - app_public: None, policy: Some(InstancePolicyUpdateRequest { single_community_enabled: None, single_community_name: None, @@ -759,10 +744,7 @@ fn build_policy_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { services, deferred_phone_gate, }), - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } @@ -826,11 +808,6 @@ fn build_integrations_update(form: &MultiValueForm) -> InstanceConfigUpdateReque _ => None, }; InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, - app_public: None, - policy: None, integrations: Some(InstanceIntegrationsUpdateRequest { gif: Some(InstanceGifIntegrationUpdateRequest { klipy_api_key: clean("integration_klipy_api_key"), @@ -871,9 +848,7 @@ fn build_integrations_update(form: &MultiValueForm) -> InstanceConfigUpdateReque keys: bluesky_keys, }), }), - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } @@ -883,12 +858,6 @@ fn build_media_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { .and_then(|value| value.trim().parse::().ok()) }; InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, - app_public: None, - policy: None, - integrations: None, media: Some(InstanceMediaUpdateRequest { attachment_decay: Some(InstanceAttachmentDecayUpdateRequest { enabled: Some(form.bool_value("media_attachment_decay_enabled")), @@ -902,8 +871,7 @@ fn build_media_update(form: &MultiValueForm) -> InstanceConfigUpdateRequest { renew_window_days: form.parse_u32("media_attachment_decay_renew_window_days"), }), }), - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } @@ -932,10 +900,6 @@ fn build_smtp_test_request(form: &MultiValueForm) -> Result InstanceConfigUpdateRequest { InstanceConfigUpdateRequest { - gateway_rollout: None, - registration: None, - sso: None, - app_public: None, policy: Some(InstancePolicyUpdateRequest { single_community_enabled: Some(enabled), single_community_name: None, @@ -944,10 +908,7 @@ fn build_single_community_update(enabled: bool) -> InstanceConfigUpdateRequest { services: None, deferred_phone_gate: None, }), - integrations: None, - media: None, - voice_noise_suppression: None, - experiment_delivery: None, + ..Default::default() } } @@ -1273,11 +1234,11 @@ mod tests { } #[test] - fn build_voice_noise_suppression_update_collects_backends_and_clamps_numbers() { + fn build_voice_noise_suppression_update_collects_backends_and_validates_numbers() { let form = MultiValueForm::parse( - b"voice_ns_enabled=true&voice_ns_allow_user_override=on&voice_ns_default_backend=rnnoise&voice_ns_enabled_backends%5B%5D=deep_filter&voice_ns_enabled_backends%5B%5D=none&voice_ns_enabled_backends%5B%5D=bogus&voice_ns_rollout_basis_points=99999&voice_ns_suppression_strength=250&voice_ns_rollout_salt=%20voice-ns-v2%20", + b"voice_ns_enabled=true&voice_ns_allow_user_override=on&voice_ns_default_backend=rnnoise&voice_ns_enabled_backends%5B%5D=deep_filter&voice_ns_enabled_backends%5B%5D=none&voice_ns_enabled_backends%5B%5D=none&voice_ns_rollout_basis_points=10000&voice_ns_suppression_strength=100&voice_ns_rollout_salt=%20voice-ns-v2%20", ); - let request = build_voice_noise_suppression_update(&form); + let request = build_voice_noise_suppression_update(&form).expect("valid form"); let update = request .voice_noise_suppression .expect("voice noise suppression update"); @@ -1303,25 +1264,19 @@ mod tests { #[test] fn build_voice_noise_suppression_update_leaves_the_feature_inert_when_nothing_is_submitted() { let form = MultiValueForm::parse(b"_csrf=token"); - let request = build_voice_noise_suppression_update(&form); - let update = request - .voice_noise_suppression - .expect("voice noise suppression update"); - assert_eq!(update.enabled, Some(false)); - assert_eq!(update.allow_user_override, Some(false)); - assert_eq!(update.stereo_enabled, Some(false)); - assert_eq!(update.default_backend, None); - assert_eq!(update.enabled_backends, Some(Vec::new())); - assert_eq!(update.rollout_basis_points, None); - assert_eq!(update.rollout_salt, None); - assert_eq!(update.included_user_ids, Some(Vec::new())); - assert_eq!(update.excluded_user_ids, Some(Vec::new())); - assert_eq!(update.guild_overrides, Some(Vec::new())); - assert_eq!(update.suppression_strength, None); - assert!(request.gateway_rollout.is_none()); - assert!(request.policy.is_none()); - assert!(request.media.is_none()); - assert!(request.experiment_delivery.is_none()); + let request = build_voice_noise_suppression_update(&form).expect("valid form"); + assert_eq!( + serde_json::to_value(request).expect("serializable update"), + serde_json::json!({"voice_noise_suppression": { + "enabled": false, + "allow_user_override": false, + "stereo_enabled": false, + "enabled_backends": [], + "included_user_ids": [], + "excluded_user_ids": [], + "guild_overrides": [], + }}) + ); } #[test] @@ -1330,6 +1285,7 @@ mod tests { b"voice_ns_included_user_ids=1500000000000000001%0A1500000000000000002&voice_ns_excluded_user_ids=1500000000000000003%2C%201500000000000000004", ); let update = build_voice_noise_suppression_update(&form) + .expect("valid form") .voice_noise_suppression .expect("voice noise suppression update"); assert_eq!( @@ -1351,7 +1307,8 @@ mod tests { #[test] fn parse_voice_noise_suppression_user_ids_splits_newlines_and_commas() { assert_eq!( - parse_voice_noise_suppression_user_ids(" 1 ,2\n3\r\n 4 ,, 5 "), + parse_voice_noise_suppression_user_ids(" 1 ,2\n3\r\n 4 ,, 5 ", "Included user IDs") + .expect("valid IDs"), vec![ "1".to_owned(), "2".to_owned(), @@ -1365,111 +1322,167 @@ mod tests { #[test] fn parse_voice_noise_suppression_user_ids_dedupes_preserving_order() { assert_eq!( - parse_voice_noise_suppression_user_ids("20,10,20,10,30"), + parse_voice_noise_suppression_user_ids("20,10,20,10,30", "Included user IDs") + .expect("valid IDs"), vec!["20".to_owned(), "10".to_owned(), "30".to_owned()] ); } #[test] fn parse_voice_noise_suppression_user_ids_rejects_non_digit_and_overlong_values() { - assert!( - parse_voice_noise_suppression_user_ids( - "abc,12a,-1,1.0, ,999999999999999999999,