openapi: "3.0.3" info: title: "e621 API" version: "2da4b89799b7799a4920adfe14112939976b4fcd" description: | An API for accessing user information and other resources on e621 and e926. The `x-access-level` extension declares the minimum privilege level for an operation. Most values name a user level, and the level named plus every level above it is granted access. In ascending order the levels are `anonymous`, `blocked`, `member`, `privileged`, `former_staff`, `staff`, `janitor`, `moderator` and `admin`. The value `logged_in` means any authenticated account regardless of level. `approver`, `bd_staff` and `bd_auditor` name a per-user flag on the account instead of a level: `can_approve_posts`, `is_bd_staff` and `is_bd_auditor`. servers: - url: "https://e621.net" description: "Production server for e621" - url: "https://e926.net" description: "SFW server for e926" security: - {} - BasicAuth: [] - ApiKeyLogin: [] ApiKeyQuery: [] paths: /posts.json: get: operationId: "getPosts" x-access-level: "anonymous" tags: - "posts" summary: "Get a list of posts" description: | Returns a list of posts filtered by tags. When `v2=true`, the response uses the v2 Post format selected by `mode` (`basic` default, `extended`, or `thumbnail`). Otherwise the legacy format wrapped in `{ "posts": [...] }` is returned. parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of posts to retrieve per page" schema: type: "integer" - name: "tags" in: "query" required: false description: "Filter posts by tags" schema: type: "string" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" responses: 200: description: "A list of posts matching the search criteria" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "posts" description: "Legacy response (default, or when `v2` is not \"true\"). The post array is wrapped under `posts`." properties: posts: type: "array" items: $ref: "#/components/schemas/LegacyPost" - type: "array" x-format: "v2" x-mode: "basic" description: "v2 basic format response (when `v2=true` and `mode` is unset or `basic`)." items: $ref: "#/components/schemas/BasicPost" - type: "array" x-format: "v2" x-mode: "extended" description: "v2 extended format response (when `v2=true` and `mode=extended`)." items: $ref: "#/components/schemas/Post" - type: "array" x-format: "v2" x-mode: "thumbnail" description: "v2 thumbnail format response (when `v2=true` and `mode=thumbnail`)." items: $ref: "#/components/schemas/ThumbnailPost" 400: description: "Invalid request parameters" 500: description: "Server error" /posts/{id}.json: get: operationId: "getPost" x-access-level: "anonymous" tags: - "posts" summary: "Get a post by ID" description: | Returns detailed information about a specific post identified by its ID. When `v2=true`, the response uses the v2 Post format selected by `mode` (`basic` default, `extended`, or `thumbnail`). Otherwise the legacy format wrapped in `{ "post": {...} }` is returned. parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to retrieve" schema: type: "integer" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" responses: 200: description: "Successful response containing post details" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "post" description: "Legacy response (default, or when `v2` is not \"true\"). The post is wrapped under `post`." properties: post: $ref: "#/components/schemas/LegacyPost" - $ref: "#/components/schemas/BasicPost" x-format: "v2" x-mode: "basic" - $ref: "#/components/schemas/Post" x-format: "v2" x-mode: "extended" - $ref: "#/components/schemas/ThumbnailPost" x-format: "v2" x-mode: "thumbnail" 404: description: "Post not found" 500: description: "Server error" put: operationId: "updatePost" x-access-level: "member" tags: - "posts" summary: "Update a post" description: | Updates a post's tags, sources, rating, parent, or description. The set of accepted fields widens with the requester's level; sending a field above the requester's level is rejected with 403. `tag_string_diff` takes precedence over `tag_string`, and `source_diff` over `source`. When `v2=true`, the response uses the v2 Post format selected by `mode` (`basic` default, `extended`, or `thumbnail`). Otherwise the legacy format wrapped in `{ "post": {...} }` is returned. parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to update" schema: type: "integer" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdatePostBody" responses: 200: description: "The post after the update was applied" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "post" description: "Legacy response (default, or when `v2` is not \"true\"). The post is wrapped under `post`." properties: post: $ref: "#/components/schemas/LegacyPost" - $ref: "#/components/schemas/BasicPost" x-format: "v2" x-mode: "basic" - $ref: "#/components/schemas/Post" x-format: "v2" x-mode: "extended" - $ref: "#/components/schemas/ThumbnailPost" x-format: "v2" x-mode: "thumbnail" 403: description: "Access denied, the edit throttle was hit, or a field above the requester's level was sent" 404: description: "Post not found" /users.json: get: operationId: "getUsers" x-access-level: "anonymous" tags: - "users" summary: "Get a list of users" description: "Returns a list of users based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of users to retrieve per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by user ID" schema: type: "string" - name: "search[name]" in: "query" required: false description: "Filter by username" schema: type: "string" - name: "search[about]" in: "query" required: false description: "Filter by user's \"About\" section" schema: type: "string" - name: "search[avatar_id]" in: "query" required: false description: "Filter by avatar ID" schema: type: "integer" - name: "search[level]" in: "query" required: false description: "Filter by user's access level" schema: type: "integer" - name: "search[min_level]" in: "query" required: false description: "Filter by minimum access level" schema: type: "integer" - name: "search[max_level]" in: "query" required: false description: "Filter by maximum access level" schema: type: "integer" - name: "search[can_upload_free]" in: "query" required: false description: "Filter by upload permissions" schema: type: "boolean" - name: "search[can_approve_posts]" in: "query" required: false description: "Filter by post approval permissions" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Order the results by a specific field" schema: $ref: "#/components/schemas/GetUsersSearchOrder" responses: 200: description: "A list of users matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/User" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createUser" x-access-level: "anonymous" tags: - "users" summary: "Create a new user account" description: "Registers a new user account. Only available when not logged in and signups are enabled." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateUserBody" responses: 201: description: "User account created" content: application/json: schema: $ref: "#/components/schemas/User" 422: description: "Validation error" /users/{id}.json: get: operationId: "getUser" x-access-level: "anonymous" tags: - "users" summary: "Get user information by ID or username" description: "Returns detailed information about a user identified by their ID or username." parameters: - name: "id" in: "path" required: true description: "The ID or username of the user to retrieve" schema: type: "string" description: "Can be either the user's ID (integer) or username (string)" responses: 200: description: "Successful response containing user details" content: application/json: schema: $ref: "#/components/schemas/UserProfile" 404: description: "User not found" 500: description: "Server error" patch: operationId: "updateUser" x-access-level: "logged_in" tags: - "users" summary: "Update the current user's settings" description: "Updates the currently authenticated user's account settings. Users can only update their own account unless they are an admin." parameters: - name: "id" in: "path" required: true description: "The ID of the user to update (must be the current user unless admin)" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateUserBody" responses: 204: description: "User updated successfully" 403: description: "Access denied" 422: description: "Validation error" /users/me.json: get: operationId: "getCurrentUser" x-access-level: "anonymous" tags: - "users" summary: "Get the current authenticated user" description: "Returns the currently authenticated user's full profile information." responses: 200: description: "Current user details" content: application/json: schema: $ref: "#/components/schemas/UserProfile" 401: description: "Not authenticated" /users/{id}/upload_limit.json: get: operationId: "getUserUploadLimit" x-access-level: "logged_in" tags: - "users" summary: "Get a user's upload limit information" description: "Returns detailed upload limit information for a user." parameters: - name: "id" in: "path" required: true description: "The ID or username of the user" schema: type: "string" responses: 200: description: "User upload limit information" content: application/json: schema: $ref: "#/components/schemas/UserProfile" 404: description: "User not found" /dmails.json: get: operationId: "getDmails" x-access-level: "member" tags: - "dmails" summary: "Get a list of DMails" description: "Returns a list of DMails for the currently authenticated user." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of DMails to retrieve per page" schema: type: "integer" - name: "search[title_matches]" in: "query" required: false description: "Filter by title text" schema: type: "string" - name: "search[message_matches]" in: "query" required: false description: "Filter by message body text" schema: type: "string" - name: "search[to_name]" in: "query" required: false description: "Filter by recipient username" schema: type: "string" - name: "search[to_id]" in: "query" required: false description: "Filter by recipient user ID" schema: type: "integer" - name: "search[from_name]" in: "query" required: false description: "Filter by sender username" schema: type: "string" - name: "search[from_id]" in: "query" required: false description: "Filter by sender user ID" schema: type: "integer" - name: "search[is_read]" in: "query" required: false description: "Filter by read status" schema: type: "boolean" - name: "search[is_deleted]" in: "query" required: false description: "Filter by deleted status" schema: type: "boolean" responses: 200: description: "A list of DMails" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Dmail" 403: description: "Access denied" /dmails/{id}.json: get: operationId: "getDmail" x-access-level: "member" tags: - "dmails" summary: "Get a DMail by ID" description: "Returns a specific DMail. Only visible to the owner, or moderators for system/ticketed DMails." parameters: - name: "id" in: "path" required: true description: "The ID of the DMail" schema: type: "integer" responses: 200: description: "DMail details" content: application/json: schema: $ref: "#/components/schemas/Dmail" 403: description: "Access denied" 404: description: "DMail not found" delete: operationId: "deleteDmail" x-access-level: "member" tags: - "dmails" summary: "Delete a DMail" description: "Marks a DMail as deleted and read." parameters: - name: "id" in: "path" required: true description: "The ID of the DMail" schema: type: "integer" responses: 200: description: "DMail deleted" 403: description: "Access denied" 404: description: "DMail not found" /dmails/{id}/mark_as_read.json: put: operationId: "markDmailAsRead" x-access-level: "member" tags: - "dmails" summary: "Mark a DMail as read" description: "Marks a specific DMail as read and decrements the unread count." parameters: - name: "id" in: "path" required: true description: "The ID of the DMail" schema: type: "integer" responses: 200: description: "DMail marked as read" 403: description: "Access denied" 404: description: "DMail not found" /dmails/{id}/mark_as_unread.json: put: operationId: "markDmailAsUnread" x-access-level: "member" tags: - "dmails" summary: "Mark a DMail as unread" description: "Marks a specific DMail as unread and increments the unread count." parameters: - name: "id" in: "path" required: true description: "The ID of the DMail" schema: type: "integer" responses: 200: description: "DMail marked as unread" 403: description: "Access denied" 404: description: "DMail not found" /dmails/mark_all_as_read.json: put: operationId: "markAllDmailsAsRead" x-access-level: "member" tags: - "dmails" summary: "Mark all DMails as read" description: "Marks all of the current user's unread DMails as read and resets the unread count." responses: 200: description: "All DMails marked as read" 403: description: "Access denied" /api_keys.json: get: operationId: "getApiKeys" x-access-level: "member" tags: - "api_keys" summary: "Get a list of API keys" description: "Returns a list of the current user's API keys. Requires reauthentication." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of API keys to retrieve per page" schema: type: "integer" - name: "search[name_matches]" in: "query" required: false description: "Filter by key name" schema: type: "string" - name: "search[is_expired]" in: "query" required: false description: "Filter by expired status" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Sort order" schema: type: "string" responses: 200: description: "A list of API keys" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ApiKey" 403: description: "Access denied" post: operationId: "createApiKey" x-access-level: "member" tags: - "api_keys" summary: "Create a new API key" description: "Creates a new API key for the current user. Requires reauthentication." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateApiKeyBody" responses: 201: description: "API key created" content: application/json: schema: $ref: "#/components/schemas/ApiKey" 422: description: "Validation error" /api_keys/{id}.json: delete: operationId: "deleteApiKey" x-access-level: "member" tags: - "api_keys" summary: "Delete an API key" description: "Permanently deletes an API key. Requires reauthentication." parameters: - name: "id" in: "path" required: true description: "The ID of the API key" schema: type: "integer" responses: 200: description: "API key deleted" 404: description: "API key not found" /api_keys/{id}/regenerate.json: post: operationId: "regenerateApiKey" x-access-level: "member" tags: - "api_keys" summary: "Regenerate an expired API key" description: "Regenerates an expired API key with a new token and expiration. Only expired keys can be regenerated." parameters: - name: "id" in: "path" required: true description: "The ID of the API key" schema: type: "integer" responses: 201: description: "API key regenerated" content: application/json: schema: $ref: "#/components/schemas/ApiKey" 422: description: "API key is not expired" /bans.json: get: operationId: "getBans" x-access-level: "anonymous" tags: - "bans" summary: "Get a list of bans" description: "Returns a list of bans based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of bans to retrieve per page" schema: type: "integer" - name: "search[user_id]" in: "query" required: false description: "Filter by banned user ID" schema: type: "integer" - name: "search[user_name]" in: "query" required: false description: "Filter by banned username" schema: type: "string" - name: "search[banner_id]" in: "query" required: false description: "Filter by staff user ID who issued the ban" schema: type: "integer" - name: "search[banner_name]" in: "query" required: false description: "Filter by staff username who issued the ban" schema: type: "string" - name: "search[reason_matches]" in: "query" required: false description: "Filter by ban reason text" schema: type: "string" - name: "search[expired]" in: "query" required: false description: "Filter by expired status (true = past bans, false = active bans)" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Sort order" schema: $ref: "#/components/schemas/GetBansSearchOrder" responses: 200: description: "A list of bans" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Ban" 400: description: "Invalid request parameters" /bans/{id}.json: get: operationId: "getBan" x-access-level: "anonymous" tags: - "bans" summary: "Get a ban by ID" description: "Returns details of a specific ban." parameters: - name: "id" in: "path" required: true description: "The ID of the ban" schema: type: "integer" responses: 200: description: "Ban details" content: application/json: schema: $ref: "#/components/schemas/Ban" 404: description: "Ban not found" /user_name_change_requests.json: get: operationId: "getUserNameChangeRequests" x-access-level: "moderator" tags: - "user_name_change_requests" summary: "Get a list of name change requests" description: "Returns a list of user name change requests." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of requests to retrieve per page" schema: type: "integer" - name: "search[original_name]" in: "query" required: false description: "Filter by original username" schema: type: "string" - name: "search[desired_name]" in: "query" required: false description: "Filter by desired username" schema: type: "string" responses: 200: description: "A list of name change requests" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/UserNameChangeRequest" 403: description: "Access denied" post: operationId: "createUserNameChangeRequest" x-access-level: "member" tags: - "user_name_change_requests" summary: "Change the current user's name" description: "Files a name change request for the authenticated user, which is applied immediately." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateUserNameChangeRequestBody" responses: 302: description: "Redirect to the created name change request" 403: description: "Access denied" /user_name_change_requests/{id}.json: get: operationId: "getUserNameChangeRequest" x-access-level: "member" tags: - "user_name_change_requests" summary: "Get a name change request by ID" description: "Returns details of a specific name change request. Members can view their own requests, moderators can view all." parameters: - name: "id" in: "path" required: true description: "The ID of the name change request" schema: type: "integer" responses: 200: description: "Name change request details" content: application/json: schema: $ref: "#/components/schemas/UserNameChangeRequest" 403: description: "Access denied" 404: description: "Name change request not found" delete: operationId: "destroyUserNameChangeRequest" x-access-level: "moderator" tags: - "user_name_change_requests" summary: "Delete a name change request" description: "Removes a name change request from the history. The username itself is not reverted." parameters: - name: "id" in: "path" required: true description: "The ID of the name change request" schema: type: "integer" responses: 302: description: "Redirect to the name change request index" 403: description: "Access denied" 404: description: "Name change request not found" /staff_notes.json: get: operationId: "getStaffNotes" x-access-level: "staff" tags: - "staff_notes" summary: "Get a list of staff notes" description: "Returns a list of staff notes. Requires staff-level access." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of staff notes to retrieve per page" schema: type: "integer" - name: "search[user_id]" in: "query" required: false description: "Filter by subject user ID" schema: type: "integer" - name: "search[user_name]" in: "query" required: false description: "Filter by subject username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by note creator user ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by note creator username" schema: type: "string" - name: "search[updater_id]" in: "query" required: false description: "Filter by note updater user ID" schema: type: "integer" - name: "search[updater_name]" in: "query" required: false description: "Filter by note updater username" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Filter by note body text" schema: type: "string" - name: "search[without_system_user]" in: "query" required: false description: "Exclude notes created by the system user" schema: type: "boolean" - name: "search[include_deleted]" in: "query" required: false description: "Include deleted notes" schema: type: "boolean" responses: 200: description: "A list of staff notes" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/StaffNote" 403: description: "Access denied" post: operationId: "createStaffNote" x-access-level: "staff" tags: - "staff_notes" summary: "Create a staff note" description: "Creates a new staff note on a user. Requires staff-level access." parameters: - name: "user_id" in: "query" required: true description: "The ID of the user to add the note to" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateStaffNoteBody" responses: 201: description: "Staff note created" content: application/json: schema: $ref: "#/components/schemas/StaffNote" 403: description: "Access denied" 422: description: "Validation error" /staff_notes/{id}.json: get: operationId: "getStaffNote" x-access-level: "staff" tags: - "staff_notes" summary: "Get a staff note by ID" description: "Returns details of a specific staff note. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The ID of the staff note" schema: type: "integer" responses: 200: description: "Staff note details" content: application/json: schema: $ref: "#/components/schemas/StaffNote" 403: description: "Access denied" 404: description: "Staff note not found" put: operationId: "updateStaffNote" x-access-level: "staff" tags: - "staff_notes" summary: "Update a staff note" description: "Rewrites the body of a staff note. Only the note's creator or an admin may do this." parameters: - name: "id" in: "path" required: true description: "The ID of the staff note" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateStaffNoteBody" responses: 302: description: "Redirect back to the referring page, or to the staff note index" 403: description: "Access denied" 404: description: "Staff note not found" /tickets.json: get: operationId: "getTickets" x-access-level: "anonymous" tags: - "tickets" summary: "Get a list of tickets" description: "Returns a list of tickets based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of tickets to retrieve per page" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the ticket" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the ticket" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter by ticket ID" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by the creator's username" schema: type: "string" - name: "search[accused_name]" in: "query" required: false description: "Filter by the accused user's username" schema: type: "string" - name: "search[claimant_name]" in: "query" required: false description: "Filter by the claimant's username" schema: type: "string" - name: "search[reason]" in: "query" required: false description: "Filter by the reason for the ticket" schema: type: "string" - name: "search[qtype]" in: "query" required: false description: "Filter by the type of the ticket (e.g., user, comment, post)" schema: $ref: "#/components/schemas/TicketQtype" - name: "search[status]" in: "query" required: false description: "Filter by the status of the ticket" schema: $ref: "#/components/schemas/GetTicketsSearchStatus" - name: "search[disp_id]" in: "query" required: false description: "Filter by the reported content ID" schema: type: "integer" responses: 200: description: "A list of tickets matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Ticket" 400: description: "Invalid request parameters" 500: description: "Server error" /tickets/{id}.json: get: operationId: "getTicket" x-access-level: "member" tags: - "tickets" summary: "Get a ticket by ID" description: "Returns detailed information about a specific ticket identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the ticket to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing ticket details" content: application/json: schema: $ref: "#/components/schemas/Ticket" 404: description: "Ticket not found" 500: description: "Server error" put: operationId: "updateTicket" x-access-level: "moderator" tags: - "tickets" summary: "Update a ticket" description: "Updates a ticket's status and response. Automatically claims the ticket for the current user." parameters: - name: "id" in: "path" required: true description: "The unique ID of the ticket" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateTicketBody" responses: 204: description: "The updated ticket" 422: description: "Validation error" 403: description: "Access denied" /tickets/{id}/claim.json: post: operationId: "claimTicket" x-access-level: "moderator" tags: - "tickets" summary: "Claim a ticket" description: "Claims a pending ticket to indicate you are handling it." parameters: - name: "id" in: "path" required: true description: "The unique ID of the ticket" schema: type: "integer" responses: 201: description: "The claimed ticket" content: application/json: schema: $ref: "#/components/schemas/Ticket" 403: description: "Access denied" /tickets/{id}/unclaim.json: post: operationId: "unclaimTicket" x-access-level: "moderator" tags: - "tickets" summary: "Unclaim a ticket" description: "Releases your claim on a ticket so others can handle it." parameters: - name: "id" in: "path" required: true description: "The unique ID of the ticket" schema: type: "integer" responses: 201: description: "The unclaimed ticket" content: application/json: schema: $ref: "#/components/schemas/Ticket" 403: description: "Access denied" /appeals.json: get: operationId: "getAppeals" x-access-level: "anonymous" tags: - "appeals" summary: "Get a list of appeals" description: | Returns appeals visible to the current user. Non-staff users only see their own appeals. Several search filters are restricted to staff. parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of appeals to retrieve per page" schema: type: "integer" - name: "search[qtype]" in: "query" required: false description: "Filter by appeal type" schema: $ref: "#/components/schemas/AppealQtype" - name: "search[status]" in: "query" required: false description: "Filter by appeal status" schema: $ref: "#/components/schemas/GetAppealsSearchStatus" - name: "search[order]" in: "query" required: false description: "Sort order" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator ID. Non-staff may only filter on their own ID." schema: type: "integer" - name: "search[disp_id]" in: "query" required: false description: "Filter by the appealed content ID (staff only)" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username (staff only)" schema: type: "string" - name: "search[accused_name]" in: "query" required: false description: "Filter by accused username (staff only)" schema: type: "string" - name: "search[accused_id]" in: "query" required: false description: "Filter by accused user ID (staff only)" schema: type: "integer" - name: "search[claimant_id]" in: "query" required: false description: "Filter by claimant ID (staff only)" schema: type: "integer" - name: "search[claimant_name]" in: "query" required: false description: "Filter by claimant username (staff only)" schema: type: "string" - name: "search[reason]" in: "query" required: false description: "Filter by reason text (staff only)" schema: type: "string" responses: 200: description: "A list of appeals matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Appeal" 500: description: "Server error" /appeals/{id}.json: get: operationId: "getAppeal" x-access-level: "member" tags: - "appeals" summary: "Get an appeal by ID" description: "Returns detailed information about a specific appeal." parameters: - name: "id" in: "path" required: true description: "The unique ID of the appeal to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing appeal details" content: application/json: schema: $ref: "#/components/schemas/Appeal" 403: description: "Access denied" 404: description: "Appeal not found" put: operationId: "updateAppeal" x-access-level: "janitor" tags: - "appeals" summary: "Update an appeal" description: | Updates an appeal's status and response. Claims the appeal for the current user. If already claimed by someone else, the request redirects to a confirmation page unless `force_claim=true` is set. parameters: - name: "id" in: "path" required: true description: "The unique ID of the appeal" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateAppealBody" responses: 204: description: "The updated appeal" 403: description: "Access denied" 422: description: "Validation error" /appeals/{id}/claim.json: post: operationId: "claimAppeal" x-access-level: "janitor" tags: - "appeals" summary: "Claim an appeal" description: "Claims a pending appeal to indicate you are handling it." parameters: - name: "id" in: "path" required: true description: "The unique ID of the appeal" schema: type: "integer" responses: 201: description: "The claimed appeal" content: application/json: schema: $ref: "#/components/schemas/Appeal" 403: description: "Access denied" /appeals/{id}/unclaim.json: post: operationId: "unclaimAppeal" x-access-level: "janitor" tags: - "appeals" summary: "Unclaim an appeal" description: "Releases the current user's claim on an appeal. Approved appeals cannot be unclaimed." parameters: - name: "id" in: "path" required: true description: "The unique ID of the appeal" schema: type: "integer" responses: 201: description: "The unclaimed appeal" content: application/json: schema: $ref: "#/components/schemas/Appeal" 403: description: "Access denied" /user_feedbacks.json: get: operationId: "getUserFeedbacks" x-access-level: "anonymous" tags: - "user_feedbacks" summary: "Get a list of user feedbacks" description: "Returns a list of user feedbacks based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of feedbacks to retrieve per page" schema: type: "integer" - name: "search[category]" in: "query" required: false description: "Filter by feedback category" schema: $ref: "#/components/schemas/UserFeedbackCategory" - name: "search[deleted]" in: "query" required: false description: "Filter by deletion status of the feedback" schema: $ref: "#/components/schemas/GetUserFeedbacksSearchDeleted" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the feedback" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the feedback" schema: type: "string" responses: 200: description: "A list of user feedbacks matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/UserFeedback" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createUserFeedback" x-access-level: "moderator" tags: - "user_feedbacks" summary: "Create a user feedback" description: "Leaves feedback on a user. The subject may be given by ID or by name, and may not be the creator." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateUserFeedbackBody" responses: 201: description: "User feedback created" content: application/json: schema: $ref: "#/components/schemas/UserFeedback" 403: description: "Access denied" 422: description: "Validation error" /user_feedbacks/{id}.json: get: operationId: "getUserFeedback" x-access-level: "anonymous" tags: - "user_feedbacks" summary: "Get a user feedback by ID" description: "Returns detailed information about a specific user feedback identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the user feedback to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing user feedback details" content: application/json: schema: $ref: "#/components/schemas/UserFeedback" 404: description: "User feedback not found" 500: description: "Server error" put: operationId: "updateUserFeedback" x-access-level: "moderator" tags: - "user_feedbacks" summary: "Update a user feedback" description: "Updates the body and/or category of an existing user feedback." parameters: - name: "id" in: "path" required: true description: "The unique ID of the user feedback to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateUserFeedbackBody" responses: 204: description: "Successfully updated user feedback" 403: description: "Not authorized to edit this feedback" 404: description: "User feedback not found" 422: description: "Validation error" delete: operationId: "destroyUserFeedback" x-access-level: "moderator" tags: - "user_feedbacks" summary: "Permanently destroy a user feedback" description: "Removes a user feedback from the database. Only an admin, or the moderator who created it, may destroy it." parameters: - name: "id" in: "path" required: true description: "The unique ID of the user feedback" schema: type: "integer" responses: 204: description: "User feedback destroyed" 403: description: "Not authorized to destroy this feedback" 404: description: "User feedback not found" /user_feedbacks/{id}/delete.json: put: operationId: "deleteUserFeedback" x-access-level: "moderator" tags: - "user_feedbacks" summary: "Soft-delete a user feedback" description: "Marks a user feedback as deleted without permanently removing it." parameters: - name: "id" in: "path" required: true description: "The unique ID of the user feedback to delete" schema: type: "integer" responses: 200: description: "Successfully deleted user feedback" 403: description: "Not authorized to delete this feedback" 404: description: "User feedback not found" /user_feedbacks/{id}/undelete.json: put: operationId: "undeleteUserFeedback" x-access-level: "moderator" tags: - "user_feedbacks" summary: "Undelete a user feedback" description: "Restores a previously soft-deleted user feedback." parameters: - name: "id" in: "path" required: true description: "The unique ID of the user feedback to undelete" schema: type: "integer" responses: 200: description: "Successfully undeleted user feedback" 403: description: "Not authorized to undelete this feedback" 404: description: "User feedback not found" /post_approvals.json: get: operationId: "getPostApprovals" x-access-level: "anonymous" tags: - "approvals" summary: "Get a list of post approvals" description: "Returns a list of post approvals based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of approvals to retrieve per page" schema: type: "integer" - name: "search[user_name]" in: "query" required: false description: "Filter approvals by approver username" schema: type: "integer" - name: "search[post_tags_match]" in: "query" required: false description: "Filter approvals by matching post tagss" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the approval" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the approval" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter by approval ID" schema: type: "string" responses: 200: description: "A list of approvals matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Approval" 400: description: "Invalid request parameters" 500: description: "Server error" /uploads.json: get: operationId: "getUploads" x-access-level: "staff" tags: - "uploads" summary: "Get a list of uploads" description: "Returns a list of uploads based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of uploads to retrieve per page" schema: type: "integer" - name: "search[uploader_name]" in: "query" required: false description: "Filter uploads by uploader's username" schema: type: "string" - name: "search[post_tags_match]" in: "query" required: false description: "Filter uploads by post tags" schema: type: "string" - name: "search[source_matches]" in: "query" required: false description: "Filter uploads by source" schema: type: "string" - name: "search[status]" in: "query" required: false description: "Filter uploads by status" schema: $ref: "#/components/schemas/GetUploadsSearchStatus" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the upload" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the upload" schema: type: "string" responses: 200: description: "A list of uploads matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Upload" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createUpload" x-access-level: "member" tags: - "uploads" summary: "Upload a post" description: "Creates a new upload from either a file or a direct URL. On success the created post's ID is returned." requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/CreateUploadBody" responses: 200: description: "The upload succeeded and a post was created" content: application/json: schema: type: "object" properties: success: type: "boolean" location: type: "string" post_id: type: "integer" 403: description: "Access denied, uploads are disabled, or a field above the requester's level was sent" 412: description: "The upload was rejected as invalid, errored, or a duplicate" content: application/json: schema: type: "object" properties: success: type: "boolean" reason: type: "string" description: "\"invalid\" or \"duplicate\"" message: type: "string" description: "Present when `reason` is \"invalid\"" location: type: "string" description: "Present when `reason` is \"duplicate\"" post_id: type: "integer" description: "The existing post, present when `reason` is \"duplicate\"" /uploads/{id}.json: get: operationId: "getUpload" x-access-level: "staff" tags: - "uploads" summary: "Get an upload by ID" description: "Returns detailed information about a specific upload identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the upload to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing upload details" content: application/json: schema: $ref: "#/components/schemas/Upload" 404: description: "Upload not found" 500: description: "Server error" /post_flags.json: get: operationId: "getPostFlags" x-access-level: "anonymous" tags: - "post_flags" summary: "Get a list of post flags" description: "Returns a list of post flags based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of post flags to retrieve per page" schema: type: "integer" - name: "search[reason_matches]" in: "query" required: false description: "Filter post flags by matching reason text" schema: type: "string" - name: "search[post_tags_match]" in: "query" required: false description: "Filter post flags by matching post tags" schema: type: "string" - name: "search[post_id]" in: "query" required: false description: "Filter post flags by post ID" schema: type: "integer" - name: "search[type]" in: "query" required: false description: "Filter post flags by type (e.g., flag or deletion)" schema: $ref: "#/components/schemas/PostFlagType" - name: "search[is_resolved]" in: "query" required: false description: "Filter post flags by resolution status" schema: type: "boolean" - name: "search[creator_name]" in: "query" required: false description: "Filter post flags by the creator's username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter post flags by creator ID" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter post flags by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter post flags by last update date" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter post flags by flag ID" schema: type: "string" responses: 200: description: "A list of post flags matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PostFlag" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createPostFlag" x-access-level: "member" tags: - "post_flags" summary: "Create a post flag" description: "Creates a new flag or deletion request for a post." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePostFlagBody" responses: 201: description: "Post flag created" content: application/json: schema: $ref: "#/components/schemas/PostFlag" 422: description: "Validation error" /post_flags/{id}.json: get: operationId: "getPostFlag" x-access-level: "anonymous" tags: - "post_flags" summary: "Get a post flag by ID" description: "Returns detailed information about a specific post flag identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post flag to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing post flag details" content: application/json: schema: $ref: "#/components/schemas/PostFlag" 404: description: "Post flag not found" 500: description: "Server error" /post_versions.json: get: operationId: "getPostVersions" x-access-level: "anonymous" tags: - "post_versions" summary: "Get a list of post versions" description: "Returns a list of post versions based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of post versions to retrieve per page" schema: type: "integer" - name: "search[updater_name]" in: "query" required: false description: "Filter post versions by the updater's username" schema: type: "string" - name: "search[post_id]" in: "query" required: false description: "Filter post versions by post ID" schema: type: "integer" - name: "search[reason]" in: "query" required: false description: "Filter post versions by the reason for the update" schema: type: "string" - name: "search[description]" in: "query" required: false description: "Filter post versions by description" schema: type: "string" - name: "search[description_changed]" in: "query" required: false description: "Filter post versions by whether the description was changed" schema: type: "boolean" - name: "search[rating_changed]" in: "query" required: false description: "Filter post versions by whether the rating was changed" schema: $ref: "#/components/schemas/GetPostVersionsSearchRatingChanged" - name: "search[rating]" in: "query" required: false description: "Filter post versions by rating" schema: $ref: "#/components/schemas/PostRating" - name: "search[parent_id]" in: "query" required: false description: "Filter post versions by parent post ID" schema: type: "integer" - name: "search[parent_id_changed]" in: "query" required: false description: "Filter post versions by whether the parent ID was changed" schema: type: "boolean" - name: "search[tags]" in: "query" required: false description: "Filter post versions by tags" schema: type: "string" - name: "search[tags_added]" in: "query" required: false description: "Filter post versions by tags added" schema: type: "string" - name: "search[tags_removed]" in: "query" required: false description: "Filter post versions by tags removed" schema: type: "string" - name: "search[locked_tags]" in: "query" required: false description: "Filter post versions by locked tags" schema: type: "string" - name: "search[locked_tags_added]" in: "query" required: false description: "Filter post versions by locked tags added" schema: type: "string" - name: "search[locked_tags_removed]" in: "query" required: false description: "Filter post versions by locked tags removed" schema: type: "string" - name: "search[source_changed]" in: "query" required: false description: "Filter post versions by whether the source was changed" schema: type: "boolean" - name: "search[uploads]" in: "query" required: false description: "Filter post versions by uploads status" schema: $ref: "#/components/schemas/GetPostVersionsSearchUploads" - name: "search[created_at]" in: "query" required: false description: "Filter post versions by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter post versions by last update date" schema: type: "string" responses: 200: description: "A list of post versions matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PostVersion" 400: description: "Invalid request parameters" 500: description: "Server error" /post_versions/{id}/undo.json: put: operationId: "undoPostVersion" x-access-level: "member" tags: - "post_versions" summary: "Undo a post version" description: "Reverts the changes made in a specific post version." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post version to undo" schema: type: "integer" responses: 200: description: "The post version was undone" 403: description: "Access denied" /post_versions/{id}/hide.json: put: operationId: "hidePostVersion" x-access-level: "bd_staff" tags: - "post_versions" summary: "Hide a post version" description: "Hides a post version from public view." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post version to hide" schema: type: "integer" responses: 302: description: "Redirects back after hiding" 403: description: "Access denied" /post_versions/{id}/unhide.json: put: operationId: "unhidePostVersion" x-access-level: "bd_staff" tags: - "post_versions" summary: "Unhide a post version" description: "Restores a hidden post version to public view." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post version to unhide" schema: type: "integer" responses: 302: description: "Redirects back after unhiding" 403: description: "Access denied" /post_replacements.json: get: operationId: "getPostReplacements" x-access-level: "anonymous" tags: - "post_replacements" summary: "Get a list of post replacements" description: "Returns a list of post replacements based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of replacements to retrieve per page" schema: type: "integer" - name: "search[md5]" in: "query" required: false description: "Filter replacements by the MD5 hash of the file" schema: type: "string" - name: "search[post_id]" in: "query" required: false description: "Filter replacements by post ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter replacements by the creator's username" schema: type: "string" - name: "search[approver_name]" in: "query" required: false description: "Filter replacements by the approver's username" schema: type: "string" - name: "search[uploader_name_on_approve]" in: "query" required: false description: "Filter replacements by the uploader's username at approval time" schema: type: "string" - name: "search[status]" in: "query" required: false description: "Filter replacements by status" schema: $ref: "#/components/schemas/GetPostReplacementsSearchStatus" - name: "search[created_at]" in: "query" required: false description: "Filter replacements by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter replacements by last update date" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter replacements by replacement ID" schema: type: "string" responses: 200: description: "A list of post replacements matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PostReplacement" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createPostReplacement" x-access-level: "member" tags: - "post_replacements" summary: "Create a post replacement" description: "Creates a new post replacement for a given post." requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/CreatePostReplacementBody" responses: 200: description: "The created post replacement" content: application/json: schema: type: "object" properties: success: type: "boolean" location: type: "string" message: type: "string" 412: description: "Replacement validation failed" 403: description: "Access denied" /post_replacements/{id}.json: delete: operationId: "destroyPostReplacement" x-access-level: "admin" tags: - "post_replacements" summary: "Destroy a post replacement" description: "Permanently removes a post replacement." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post replacement" schema: type: "integer" responses: 204: description: "The post replacement was destroyed" 403: description: "Access denied" 404: description: "Post replacement not found" /post_replacements/{id}/approve.json: put: operationId: "approvePostReplacement" x-access-level: "approver" tags: - "post_replacements" summary: "Approve a post replacement" description: "Approves a pending post replacement." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post replacement" schema: type: "integer" - name: "penalize_current_uploader" in: "query" required: false description: "Whether to penalize the current uploader" schema: type: "boolean" responses: 200: description: "The approved post replacement" content: application/json: schema: $ref: "#/components/schemas/PostReplacement" 400: description: "Replacement approval failed" 403: description: "Access denied" /post_replacements/{id}/reject.json: put: operationId: "rejectPostReplacement" x-access-level: "approver" tags: - "post_replacements" summary: "Reject a post replacement" description: "Rejects a pending post replacement." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post replacement" schema: type: "integer" responses: 200: description: "The rejected post replacement" content: application/json: schema: $ref: "#/components/schemas/PostReplacement" 403: description: "Access denied" /post_replacements/{id}/promote.json: post: operationId: "promotePostReplacement" x-access-level: "approver" tags: - "post_replacements" summary: "Promote a post replacement" description: "Promotes a post replacement to a new post." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post replacement" schema: type: "integer" responses: 200: description: "The promoted post replacement" content: application/json: schema: $ref: "#/components/schemas/LegacyPost" 422: description: "Promotion failed" 403: description: "Access denied" /post_replacements/{id}/toggle_penalize.json: put: operationId: "togglePenalizePostReplacement" x-access-level: "approver" tags: - "post_replacements" summary: "Toggle penalize on a post replacement" description: "Toggles the penalize flag on a post replacement." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post replacement" schema: type: "integer" responses: 200: description: "The updated post replacement" content: application/json: schema: $ref: "#/components/schemas/PostReplacement" 403: description: "Access denied" /mod_actions.json: get: operationId: "getModActions" x-access-level: "anonymous" tags: - "mod_actions" summary: "Get a list of moderation actions" description: "Returns a list of moderation actions based on search criteria." parameters: - name: "search[creator_name]" in: "query" required: false description: "Filter by the name of the creator of the moderation action" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by the ID of the creator of the moderation action" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the moderation action" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the moderation action" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter by the ID of the moderation action" schema: type: "string" - name: "search[action]" in: "query" required: false description: "Filter by the type of moderation action" schema: $ref: "#/components/schemas/GetModActionsSearchAction" responses: 200: description: "A list of moderation actions matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ModAction" 400: description: "Invalid request parameters" 500: description: "Server error" /mod_actions/{id}.json: get: operationId: "getModAction" x-access-level: "anonymous" tags: - "mod_actions" summary: "Get a moderation action by ID" description: "Returns detailed information about a specific moderation action identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the moderation action to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing moderation action details" content: application/json: schema: $ref: "#/components/schemas/ModAction" 404: description: "Moderation action not found" 500: description: "Server error" /bulk_update_requests.json: get: operationId: "getBulkUpdateRequests" x-access-level: "anonymous" tags: - "bulk_update_requests" summary: "Get a list of bulk update requests" description: "Returns a list of bulk update requests filtered by various criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of bulk update requests to retrieve per page" schema: type: "integer" - name: "search[user_name]" in: "query" required: false description: "Filter by the username of the creator" schema: type: "string" - name: "search[approver_name]" in: "query" required: false description: "Filter by the username of the approver" schema: type: "string" - name: "search[title_matches]" in: "query" required: false description: "Filter by the title of the request" schema: type: "string" - name: "search[script_matches]" in: "query" required: false description: "Filter by script content in the request" schema: type: "string" - name: "search[status]" in: "query" required: false description: "Filter by the status of the request" schema: $ref: "#/components/schemas/BulkUpdateRequestStatus" - name: "search[order]" in: "query" required: false description: "Order the results by a specific field" schema: $ref: "#/components/schemas/GetBulkUpdateRequestsSearchOrder" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the request" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the request" schema: type: "string" responses: 200: description: "A list of bulk update requests matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/BulkUpdateRequest" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createBulkUpdateRequest" x-access-level: "member" tags: - "bulk_update_requests" summary: "Create a bulk update request" description: "Creates a new bulk update request." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateBulkUpdateRequestBody" responses: 201: description: "The created bulk update request" content: application/json: schema: $ref: "#/components/schemas/BulkUpdateRequest" 422: description: "Validation error" 403: description: "Access denied" /bulk_update_requests/{id}.json: get: operationId: "getBulkUpdateRequest" x-access-level: "anonymous" tags: - "bulk_update_requests" summary: "Get a bulk update request by ID" description: "Returns detailed information about a specific bulk update request identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the bulk update request to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing bulk update request details" content: application/json: schema: $ref: "#/components/schemas/BulkUpdateRequest" 404: description: "Bulk update request not found" 500: description: "Server error" put: operationId: "updateBulkUpdateRequest" x-access-level: "member" tags: - "bulk_update_requests" summary: "Update a bulk update request" description: "Updates an existing bulk update request. Only the creator or admin can update." parameters: - name: "id" in: "path" required: true description: "The unique ID of the bulk update request" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateBulkUpdateRequestBody" responses: 204: description: "The updated bulk update request" 422: description: "Validation error" 403: description: "Access denied" delete: operationId: "destroyBulkUpdateRequest" x-access-level: "member" tags: - "bulk_update_requests" summary: "Reject a bulk update request" description: "Rejects a bulk update request. Only the creator or admin can reject." parameters: - name: "id" in: "path" required: true description: "The unique ID of the bulk update request" schema: type: "integer" responses: 204: description: "The bulk update request was rejected" 403: description: "Access denied" /bulk_update_requests/{id}/approve.json: post: operationId: "approveBulkUpdateRequest" x-access-level: "admin" tags: - "bulk_update_requests" summary: "Approve a bulk update request" description: "Approves and executes a bulk update request." parameters: - name: "id" in: "path" required: true description: "The unique ID of the bulk update request" schema: type: "integer" responses: 201: description: "The approved bulk update request" content: application/json: schema: $ref: "#/components/schemas/BulkUpdateRequest" 422: description: "Approval failed" 403: description: "Access denied" /tag_aliases.json: get: operationId: "getTagAliases" x-access-level: "anonymous" tags: - "tag_aliases" summary: "Get a list of tag aliases" description: "Returns a list of tag aliases filtered by various criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of tag aliases to retrieve per page" schema: type: "integer" - name: "search[name_matches]" in: "query" required: false description: "Filter by matching names" schema: type: "string" - name: "search[antecedent_name]" in: "query" required: false description: "Filter by the antecedent name of the alias" schema: type: "string" - name: "search[consequent_name]" in: "query" required: false description: "Filter by the consequent name of the alias" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by the creator's username" schema: type: "string" - name: "search[approver_name]" in: "query" required: false description: "Filter by the approver's username" schema: type: "string" - name: "search[antecedent_tag_category]" in: "query" required: false description: "Filter by the tag category of the antecedent tag" schema: type: "integer" - name: "search[consequent_tag_category]" in: "query" required: false description: "Filter by the tag category of the consequent tag" schema: type: "integer" - name: "search[status]" in: "query" required: false description: "Filter by the status of the tag alias" schema: $ref: "#/components/schemas/GetTagAliasesSearchStatus" - name: "search[order]" in: "query" required: false description: "Order the results by a specific field" schema: $ref: "#/components/schemas/GetTagAliasesSearchOrder" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the request" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the request" schema: type: "string" responses: 200: description: "A list of tag aliases matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/TagAlias" 400: description: "Invalid request parameters" 500: description: "Server error" /tag_aliases/{id}.json: get: operationId: "getTagAlias" x-access-level: "anonymous" tags: - "tag_aliases" summary: "Get a tag alias by ID" description: "Returns detailed information about a specific tag alias identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag alias to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing tag alias details" content: application/json: schema: $ref: "#/components/schemas/TagAlias" 404: description: "Tag alias not found" 500: description: "Server error" put: operationId: "updateTagAlias" x-access-level: "admin" tags: - "tag_aliases" summary: "Update a tag alias" description: "Updates a tag alias. The antecedent and consequent names can only be changed while the alias is pending." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag alias" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateTagAliasBody" responses: 204: description: "The tag alias was updated" 403: description: "Access denied" 404: description: "Tag alias not found" 422: description: "Validation error" delete: operationId: "destroyTagAlias" x-access-level: "member" tags: - "tag_aliases" summary: "Reject a tag alias" description: "Rejects a tag alias by setting its status to deleted. Allowed for an admin on an alias that is not already deleted, or for the creator of a pending alias." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag alias" schema: type: "integer" responses: 204: description: "The tag alias was rejected" 403: description: "Access denied" 404: description: "Tag alias not found" 422: description: "Validation error" /tag_implications.json: get: operationId: "getTagImplications" x-access-level: "anonymous" tags: - "tag_implications" summary: "Get a list of tag implications" description: "Returns a list of tag implications filtered by various criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of tag implications to retrieve per page" schema: type: "integer" - name: "search[name_matches]" in: "query" required: false description: "Filter by matching names" schema: type: "string" - name: "search[antecedent_name]" in: "query" required: false description: "Filter by the antecedent name of the implication" schema: type: "string" - name: "search[consequent_name]" in: "query" required: false description: "Filter by the consequent name of the implication" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by the creator's username" schema: type: "string" - name: "search[approver_name]" in: "query" required: false description: "Filter by the approver's username" schema: type: "string" - name: "search[antecedent_tag_category]" in: "query" required: false description: "Filter by the tag category of the antecedent tag" schema: type: "integer" - name: "search[consequent_tag_category]" in: "query" required: false description: "Filter by the tag category of the consequent tag" schema: type: "integer" - name: "search[status]" in: "query" required: false description: "Filter by the status of the tag implication" schema: $ref: "#/components/schemas/GetTagImplicationsSearchStatus" - name: "search[order]" in: "query" required: false description: "Order the results by a specific field" schema: $ref: "#/components/schemas/GetTagImplicationsSearchOrder" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the request" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the request" schema: type: "string" responses: 200: description: "A list of tag implications matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/TagImplication" 400: description: "Invalid request parameters" 500: description: "Server error" /tag_implications/{id}.json: get: operationId: "getTagImplication" x-access-level: "anonymous" tags: - "tag_implications" summary: "Get a tag implication by ID" description: "Returns detailed information about a specific tag implication identified by its ID." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag implication to retrieve" schema: type: "integer" responses: 200: description: "Successful response containing tag implication details" content: application/json: schema: $ref: "#/components/schemas/TagImplication" 404: description: "Tag implication not found" 500: description: "Server error" put: operationId: "updateTagImplication" x-access-level: "admin" tags: - "tag_implications" summary: "Update a tag implication" description: "Updates a tag implication. The update is only applied while the implication is pending." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag implication" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateTagImplicationBody" responses: 204: description: "The tag implication was updated" 403: description: "Access denied" 404: description: "Tag implication not found" 422: description: "Validation error" delete: operationId: "destroyTagImplication" x-access-level: "member" tags: - "tag_implications" summary: "Reject a tag implication" description: "Rejects a tag implication by setting its status to deleted. Allowed for an admin on an implication that is not already deleted, or for the creator of a pending implication." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag implication" schema: type: "integer" responses: 204: description: "The tag implication was rejected" 403: description: "Access denied" 404: description: "Tag implication not found" 422: description: "Validation error" /post_events.json: get: operationId: "getPostEvents" x-access-level: "anonymous" tags: - "post_events" summary: "Get a list of post events" description: | Returns a list of post events filtered by various criteria. When `v2=true`, the response is an unwrapped array. Otherwise the array is wrapped under `post_events`. parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of post events to retrieve per page" schema: type: "integer" - name: "search[post_id]" in: "query" required: false description: "Filter by post ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by the creator's username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by the creator's ID" schema: type: "integer" - name: "search[action]" in: "query" required: false description: "Filter by the action performed" schema: $ref: "#/components/schemas/PostEventAction" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the event" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter by event ID" schema: type: "string" - $ref: "#/components/parameters/PostV2Flag" responses: 200: description: "A list of post events matching the search criteria" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "post_events" description: "Legacy response (default). The array is wrapped under `post_events`." properties: post_events: type: "array" items: $ref: "#/components/schemas/PostEvent" - type: "array" x-format: "v2" description: "Unwrapped response (when `v2=true`)." items: $ref: "#/components/schemas/PostEvent" 400: description: "Invalid request parameters" 500: description: "Server error" /artists.json: get: operationId: "getArtists" x-access-level: "anonymous" tags: - "artists" summary: "Get a list of artists" description: "Returns a list of artists based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of artists to retrieve per page" schema: type: "integer" - name: "search[name]" in: "query" required: false description: "Filter by exact artist name" schema: type: "string" - name: "search[any_name_matches]" in: "query" required: false description: "Filter by partial name match (searches name, other names, and group name)" schema: type: "string" - name: "search[any_name_or_url_matches]" in: "query" required: false description: "Filter by name or URL match" schema: type: "string" - name: "search[url_matches]" in: "query" required: false description: "Filter by URL match" schema: type: "string" - name: "search[group_name]" in: "query" required: false description: "Filter by group name" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by the creator's username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by the creator's user ID" schema: type: "integer" - name: "search[linked_user_name]" in: "query" required: false description: "Filter by the linked user's username" schema: type: "string" - name: "search[linked_user_id]" in: "query" required: false description: "Filter by the linked user's ID" schema: type: "integer" - name: "search[is_linked]" in: "query" required: false description: "Filter by whether a user is linked" schema: type: "boolean" - name: "search[has_tag]" in: "query" required: false description: "Filter by whether the artist has a tag with posts" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Sort order" schema: $ref: "#/components/schemas/GetArtistsSearchOrder" responses: 200: description: "A list of artists matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Artist" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createArtist" x-access-level: "member" tags: - "artists" summary: "Create an artist" description: "Creates a new artist entry." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateArtistBody" responses: 201: description: "The created artist" content: application/json: schema: $ref: "#/components/schemas/Artist" 403: description: "Access denied, or a supplied attribute is not permitted at this user level" 422: description: "Validation error" /artists/{id}.json: get: operationId: "getArtist" x-access-level: "anonymous" tags: - "artists" summary: "Get an artist by ID or name" description: "Returns detailed information about a specific artist." parameters: - name: "id" in: "path" required: true description: "The artist ID or name" schema: type: "string" responses: 200: description: "Successful response containing artist details" content: application/json: schema: $ref: "#/components/schemas/Artist" 404: description: "Artist not found" put: operationId: "updateArtist" x-access-level: "member" tags: - "artists" summary: "Update an artist" description: "Updates an existing artist. Returns no content on success." parameters: - name: "id" in: "path" required: true description: "The artist ID or name" schema: type: "string" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateArtistBody" responses: 204: description: "Artist updated" 403: description: "The artist is locked and the user is not staff, or a supplied attribute is not permitted at this user level" 404: description: "Artist not found" 422: description: "Validation error" delete: operationId: "destroyArtist" x-access-level: "admin" tags: - "artists" summary: "Destroy an artist" description: "Permanently destroys an artist. An artist with any avoid posting entry, active or not, cannot be destroyed. Returns no content on success." parameters: - name: "id" in: "path" required: true description: "The artist ID or name" schema: type: "string" responses: 204: description: "The artist was destroyed" 403: description: "Access denied" 404: description: "Artist not found" /edit_histories.json: get: operationId: "getEditHistories" x-access-level: "moderator" tags: - "edit_histories" summary: "Search edit histories" description: "Returns a list of edit histories for comments, forum posts, and blips." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results to retrieve per page" schema: type: "integer" - name: "search[body_matches]" in: "query" required: false description: "Filter by body text" schema: type: "string" - name: "search[subject_matches]" in: "query" required: false description: "Filter by subject text" schema: type: "string" - name: "search[versionable_type]" in: "query" required: false description: "Filter by edited item type" schema: $ref: "#/components/schemas/GetEditHistoryType" - name: "search[versionable_id]" in: "query" required: false description: "Filter by edited item ID" schema: type: "integer" - name: "search[editor_name]" in: "query" required: false description: "Filter by editor username" schema: type: "string" - name: "search[editor_id]" in: "query" required: false description: "Filter by editor user ID" schema: type: "integer" - name: "search[order]" in: "query" required: false description: "Sort order" schema: $ref: "#/components/schemas/GetEditHistoriesSearchOrder" responses: 200: description: "A list of edit histories matching the search criteria" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/EditHistory" 400: description: "Invalid request parameters" 500: description: "Server error" /edit_histories/{id}.json: get: operationId: "getEditHistory" x-access-level: "moderator" tags: - "edit_histories" summary: "Get edit history for a specific item" description: "Returns all edit history versions for a specific comment, forum post, or blip." parameters: - name: "id" in: "path" required: true description: "The ID of the edited item" schema: type: "integer" - name: "type" in: "query" required: true description: "The type of the edited item" schema: $ref: "#/components/schemas/GetEditHistoryType" responses: 200: description: "Edit history versions for the item" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/EditHistory" 404: description: "Item not found" /comments.json: get: operationId: "searchComments" x-access-level: "anonymous" tags: - "comments" summary: "Search comments" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by comment ID" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by update date" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Filter by comment body text" schema: type: "string" - name: "search[post_id]" in: "query" required: false description: "Filter by post ID" schema: type: "integer" - name: "search[post_tags_match]" in: "query" required: false description: "Filter by post tags" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[post_note_updater_name]" in: "query" required: false description: "Filter by note updater username" schema: type: "string" - name: "search[post_note_updater_id]" in: "query" required: false description: "Filter by note updater user ID" schema: type: "integer" - name: "search[poster_id]" in: "query" required: false description: "Filter by post uploader ID" schema: type: "integer" - name: "search[poster_name]" in: "query" required: false description: "Filter by post uploader username" schema: type: "string" - name: "search[is_sticky]" in: "query" required: false description: "Filter by sticky status" schema: type: "boolean" - name: "search[do_not_bump_post]" in: "query" required: false description: "Filter by do not bump post status" schema: type: "boolean" - name: "search[is_hidden]" in: "query" required: false description: "Filter by hidden status (moderator only)" schema: type: "boolean" - name: "search[ip_addr]" in: "query" required: false description: "Filter by creator IP address (admin only)" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Sort order (post_id, score, updated_at)" schema: type: "string" - name: "search[advanced_search]" in: "query" required: false description: "Use advanced search for body_matches" schema: type: "boolean" - name: "group_by" in: "query" required: false description: "Group results by post" schema: $ref: "#/components/schemas/SearchCommentsGroupBy" responses: 200: description: "A list of comments" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Comment" post: operationId: "createComment" x-access-level: "member" tags: - "comments" summary: "Create a comment" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateCommentBody" responses: 200: description: "Comment created" content: application/json: schema: $ref: "#/components/schemas/Comment" 422: description: "Validation error" /comments/{id}.json: get: operationId: "getComment" x-access-level: "anonymous" tags: - "comments" summary: "Get a comment by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the comment" schema: type: "integer" responses: 200: description: "A comment" content: application/json: schema: $ref: "#/components/schemas/Comment" 404: description: "Comment not found" patch: operationId: "updateComment" x-access-level: "member" tags: - "comments" summary: "Update a comment" parameters: - name: "id" in: "path" required: true description: "The ID of the comment" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateCommentBody" responses: 200: description: "Comment updated" content: application/json: schema: $ref: "#/components/schemas/Comment" 422: description: "Validation error" delete: operationId: "deleteComment" x-access-level: "admin" tags: - "comments" summary: "Delete a comment" parameters: - name: "id" in: "path" required: true description: "The ID of the comment" schema: type: "integer" responses: 200: description: "Comment deleted" 404: description: "Comment not found" /comments/{id}/hide.json: post: operationId: "hideComment" x-access-level: "member" tags: - "comments" summary: "Hide a comment" parameters: - name: "id" in: "path" required: true description: "The ID of the comment" schema: type: "integer" responses: 200: description: "Comment hidden" content: application/json: schema: $ref: "#/components/schemas/Comment" 403: description: "Access denied" 404: description: "Comment not found" /comments/{id}/unhide.json: post: operationId: "unhideComment" x-access-level: "moderator" tags: - "comments" summary: "Unhide a comment" parameters: - name: "id" in: "path" required: true description: "The ID of the comment" schema: type: "integer" responses: 200: description: "Comment unhidden" content: application/json: schema: $ref: "#/components/schemas/Comment" 403: description: "Access denied" 404: description: "Comment not found" /comments/{id}/warning.json: post: operationId: "warningComment" x-access-level: "moderator" tags: - "comments" summary: "Mark or unmark a comment with a warning" parameters: - name: "id" in: "path" required: true description: "The ID of the comment" schema: type: "integer" - name: "record_type" in: "query" required: true description: "The type of warning to apply or \"unmark\" to remove" schema: $ref: "#/components/schemas/WarningBlipRecordType" responses: 200: description: "Comment warning updated" content: application/json: schema: type: "object" properties: html: type: "string" posts: type: "object" 403: description: "Access denied" 404: description: "Comment not found" /comment_votes.json: get: operationId: "searchCommentVotes" x-access-level: "moderator" tags: - "comment_votes" summary: "Search comment votes" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "search[comment_id]" in: "query" required: false description: "Filter by comment ID" schema: type: "integer" - name: "search[user_name]" in: "query" required: false description: "Filter by voter username" schema: type: "string" - name: "search[user_id]" in: "query" required: false description: "Filter by voter user ID" schema: type: "integer" - name: "search[comment_creator_id]" in: "query" required: false description: "Filter by comment creator ID" schema: type: "integer" - name: "search[comment_creator_name]" in: "query" required: false description: "Filter by comment creator username" schema: type: "string" - name: "search[timeframe]" in: "query" required: false description: "Filter by number of days ago" schema: type: "integer" - name: "search[score]" in: "query" required: false description: "Filter by vote score (1 or -1)" schema: $ref: "#/components/schemas/CreatePostVoteBodyScore" - name: "search[user_ip_addr]" in: "query" required: false description: "Filter by voter IP address (admin only)" schema: type: "string" - name: "search[duplicates_only]" in: "query" required: false description: "Show only duplicate IP votes (admin only)" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Sort order (ip_addr)" schema: type: "string" responses: 200: description: "A list of comment votes" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/CommentVote" /comment_votes/lock.json: post: operationId: "lockCommentVotes" x-access-level: "moderator" tags: - "comment_votes" summary: "Lock comment votes by ID" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LockPostVotesBody" responses: 200: description: "Comment votes locked" 403: description: "Access denied" /comment_votes/delete.json: post: operationId: "deleteCommentVotes" x-access-level: "admin" tags: - "comment_votes" summary: "Delete comment votes by ID" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LockPostVotesBody" responses: 200: description: "Comment votes deleted" 403: description: "Access denied" /comments/{comment_id}/votes.json: post: operationId: "createCommentVote" x-access-level: "member" tags: - "comment_votes" summary: "Vote on a comment" parameters: - name: "comment_id" in: "path" required: true description: "The ID of the comment to vote on" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateCommentVoteBody" responses: 200: description: "Vote registered" content: application/json: schema: type: "object" properties: score: type: "integer" description: "The new comment score" our_score: type: "integer" description: "The user's vote score (0 if unvoted)" 422: description: "Vote error" delete: operationId: "deleteCommentVote" x-access-level: "member" tags: - "comment_votes" summary: "Remove vote on a comment" parameters: - name: "comment_id" in: "path" required: true description: "The ID of the comment to unvote" schema: type: "integer" responses: 200: description: "Vote removed" 422: description: "Unvote error" /blips.json: get: operationId: "searchBlips" x-access-level: "anonymous" tags: - "blips" summary: "Search blips" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by blip ID" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by update date" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Filter by blip body text" schema: type: "string" - name: "search[response_to]" in: "query" required: false description: "Filter by parent blip ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[ip_addr]" in: "query" required: false description: "Filter by creator IP address (admin only)" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Sort order (updated_at)" schema: type: "string" responses: 200: description: "A list of blips" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Blip" post: operationId: "createBlip" x-access-level: "member" tags: - "blips" summary: "Create a blip" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateBlipBody" responses: 201: description: "Blip created" content: application/json: schema: $ref: "#/components/schemas/Blip" 422: description: "Validation error" /blips/{id}.json: get: operationId: "getBlip" x-access-level: "anonymous" tags: - "blips" summary: "Get a blip by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the blip" schema: type: "integer" responses: 200: description: "A blip" content: application/json: schema: $ref: "#/components/schemas/Blip" 404: description: "Blip not found" patch: operationId: "updateBlip" x-access-level: "member" tags: - "blips" summary: "Update a blip" parameters: - name: "id" in: "path" required: true description: "The ID of the blip" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateBlipBody" responses: 204: description: "Blip updated" 422: description: "Validation error" delete: operationId: "destroyBlip" x-access-level: "admin" tags: - "blips" summary: "Destroy a blip" description: "Permanently removes a blip. For soft-deletion, use `POST /blips/{id}/delete.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the blip" schema: type: "integer" responses: 200: description: "Blip destroyed" 404: description: "Blip not found" /blips/{id}/delete.json: post: operationId: "deleteBlip" x-access-level: "member" tags: - "blips" summary: "Soft-delete a blip" description: "Marks a blip as deleted, hiding it from normal views. Previously named `hide`." parameters: - name: "id" in: "path" required: true description: "The ID of the blip" schema: type: "integer" responses: 200: description: "Blip deleted" content: application/json: schema: $ref: "#/components/schemas/Blip" 403: description: "Access denied" 404: description: "Blip not found" /blips/{id}/undelete.json: post: operationId: "undeleteBlip" x-access-level: "moderator" tags: - "blips" summary: "Undelete a blip" description: "Restores a soft-deleted blip. Previously named `unhide`." parameters: - name: "id" in: "path" required: true description: "The ID of the blip" schema: type: "integer" responses: 200: description: "Blip undeleted" content: application/json: schema: $ref: "#/components/schemas/Blip" 403: description: "Access denied" 404: description: "Blip not found" /blips/{id}/warning.json: post: operationId: "warningBlip" x-access-level: "moderator" tags: - "blips" summary: "Mark or unmark a blip with a warning" parameters: - name: "id" in: "path" required: true description: "The ID of the blip" schema: type: "integer" - name: "record_type" in: "query" required: true description: "The type of warning to apply or \"unmark\" to remove" schema: $ref: "#/components/schemas/WarningBlipRecordType" responses: 200: description: "Blip warning updated" content: application/json: schema: type: "object" properties: html: type: "string" posts: type: "object" 403: description: "Access denied" 404: description: "Blip not found" /forum_topics.json: get: operationId: "searchForumTopics" x-access-level: "anonymous" tags: - "forum_topics" summary: "Search forum topics" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by forum topic ID" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by update date" schema: type: "string" - name: "search[title_matches]" in: "query" required: false description: "Filter by title text" schema: type: "string" - name: "search[title]" in: "query" required: false description: "Filter by exact title" schema: type: "string" - name: "search[category_id]" in: "query" required: false description: "Filter by forum category ID" schema: type: "integer" - name: "search[is_sticky]" in: "query" required: false description: "Filter by sticky status" schema: type: "boolean" - name: "search[is_locked]" in: "query" required: false description: "Filter by locked status" schema: type: "boolean" - name: "search[is_hidden]" in: "query" required: false description: "Filter by hidden status" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Sort order (sticky)" schema: type: "string" responses: 200: description: "A list of forum topics" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ForumTopic" post: operationId: "createForumTopic" x-access-level: "member" tags: - "forum_topics" summary: "Create a forum topic" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateForumTopicBody" responses: 201: description: "Forum topic created" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 422: description: "Validation error" /forum_topics/{id}.json: get: operationId: "getForumTopic" x-access-level: "anonymous" tags: - "forum_topics" summary: "Get a forum topic by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" - name: "page" in: "query" required: false description: "The page number for forum posts pagination" schema: type: "integer" responses: 200: description: "A forum topic" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 404: description: "Forum topic not found" patch: operationId: "updateForumTopic" x-access-level: "member" tags: - "forum_topics" summary: "Update a forum topic" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateForumTopicBody" responses: 204: description: "Forum topic updated" 422: description: "Validation error" delete: operationId: "deleteForumTopic" x-access-level: "admin" tags: - "forum_topics" summary: "Delete a forum topic" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 200: description: "Forum topic deleted" 404: description: "Forum topic not found" /forum_topics/{id}/hide.json: post: operationId: "hideForumTopic" x-access-level: "member" tags: - "forum_topics" summary: "Hide a forum topic" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 201: description: "Forum topic hidden" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 403: description: "Access denied" 404: description: "Forum topic not found" /forum_topics/{id}/unhide.json: post: operationId: "unhideForumTopic" x-access-level: "moderator" tags: - "forum_topics" summary: "Unhide a forum topic" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 201: description: "Forum topic unhidden" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 403: description: "Access denied" 404: description: "Forum topic not found" /forum_topics/{id}/subscribe.json: post: operationId: "subscribeForumTopic" x-access-level: "member" tags: - "forum_topics" summary: "Subscribe to a forum topic" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 200: description: "Subscribed to forum topic" 404: description: "Forum topic not found" /forum_topics/{id}/unsubscribe.json: post: operationId: "unsubscribeForumTopic" x-access-level: "member" tags: - "forum_topics" summary: "Unsubscribe from a forum topic" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 200: description: "Unsubscribed from forum topic" 404: description: "Forum topic not found" /forum_topics/mark_all_as_read.json: post: operationId: "markAllForumTopicsAsRead" x-access-level: "member" tags: - "forum_topics" summary: "Mark all forum topics as read" responses: 200: description: "All forum topics marked as read" /forum_posts.json: get: operationId: "searchForumPosts" x-access-level: "anonymous" tags: - "forum_posts" summary: "Search forum posts" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by forum post ID" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by update date" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[topic_id]" in: "query" required: false description: "Filter by forum topic ID" schema: type: "integer" - name: "search[topic_title_matches]" in: "query" required: false description: "Filter by topic title text" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Filter by post body text" schema: type: "string" - name: "search[topic_category_id]" in: "query" required: false description: "Filter by topic category ID" schema: type: "integer" - name: "search[is_hidden]" in: "query" required: false description: "Filter by hidden status" schema: type: "boolean" responses: 200: description: "A list of forum posts" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ForumPost" post: operationId: "createForumPost" x-access-level: "member" tags: - "forum_posts" summary: "Create a forum post" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateForumPostBody" responses: 201: description: "Forum post created" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 422: description: "Validation error" /forum_posts/{id}.json: get: operationId: "getForumPost" x-access-level: "anonymous" tags: - "forum_posts" summary: "Get a forum post by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 200: description: "A forum post" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 404: description: "Forum post not found" patch: operationId: "updateForumPost" x-access-level: "member" tags: - "forum_posts" summary: "Update a forum post" parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateForumPostBody" responses: 204: description: "Forum post updated" 422: description: "Validation error" delete: operationId: "deleteForumPost" x-access-level: "admin" tags: - "forum_posts" summary: "Delete a forum post" parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 200: description: "Forum post deleted" 404: description: "Forum post not found" /forum_posts/{id}/hide.json: post: operationId: "hideForumPost" x-access-level: "member" tags: - "forum_posts" summary: "Hide a forum post" parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 201: description: "Forum post hidden" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 403: description: "Access denied" 404: description: "Forum post not found" /forum_posts/{id}/unhide.json: post: operationId: "unhideForumPost" x-access-level: "moderator" tags: - "forum_posts" summary: "Unhide a forum post" parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 201: description: "Forum post unhidden" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 403: description: "Access denied" 404: description: "Forum post not found" /forum_posts/{id}/warning.json: post: operationId: "warningForumPost" x-access-level: "moderator" tags: - "forum_posts" summary: "Mark or unmark a forum post with a warning" parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" - name: "record_type" in: "query" required: true description: "The type of warning to apply or \"unmark\" to remove" schema: $ref: "#/components/schemas/WarningBlipRecordType" responses: 200: description: "Forum post warning updated" content: application/json: schema: type: "object" properties: html: type: "string" posts: type: "object" 403: description: "Access denied" 404: description: "Forum post not found" /forum_posts/{forum_post_id}/votes.json: post: operationId: "createForumPostVote" x-access-level: "member" tags: - "forum_post_votes" summary: "Vote on a forum post" parameters: - name: "forum_post_id" in: "path" required: true description: "The ID of the forum post to vote on" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateForumPostVoteBody" responses: 201: description: "Vote created" content: application/json: schema: $ref: "#/components/schemas/ForumPostVote" 403: description: "Access denied" delete: operationId: "deleteForumPostVote" x-access-level: "member" tags: - "forum_post_votes" summary: "Remove vote on a forum post" parameters: - name: "forum_post_id" in: "path" required: true description: "The ID of the forum post to unvote" schema: type: "integer" responses: 200: description: "Vote removed" 404: description: "Vote not found" get: operationId: "getForumPostVotes" x-access-level: "member" tags: - "forum_post_votes" summary: "List the votes on a forum post" description: "Only forum posts attached to a tag alias, tag implication or bulk update request are votable." parameters: - name: "forum_post_id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 200: description: "A list of forum post votes" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ForumPostVote" 403: description: "Access denied" 404: description: "Forum post not found" /tags.json: get: operationId: "searchTags" x-access-level: "anonymous" tags: - "tags" summary: "Search tags" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[name_matches]" in: "query" required: false description: "Search by tag name pattern (supports wildcards)" schema: type: "string" - name: "search[name]" in: "query" required: false description: "Filter by exact tag name (comma-separated for multiple)" schema: type: "string" - name: "search[category]" in: "query" required: false description: "Filter by tag category ID (comma-separated for multiple)" schema: type: "string" - name: "search[hide_empty]" in: "query" required: false description: "Hide tags with no posts (default true)" schema: type: "string" - name: "search[has_wiki]" in: "query" required: false description: "Filter by whether the tag has a wiki page" schema: type: "string" - name: "search[has_artist]" in: "query" required: false description: "Filter by whether the tag has an artist entry" schema: type: "string" - name: "search[is_locked]" in: "query" required: false description: "Filter by locked status" schema: type: "string" - name: "search[fuzzy_name_matches]" in: "query" required: false description: "Search by fuzzy tag name match" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Sort order for results" schema: $ref: "#/components/schemas/SearchTagsSearchOrder" responses: 200: description: "A list of tags" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Tag" /tags/{id}.json: get: operationId: "getTag" x-access-level: "anonymous" tags: - "tags" summary: "Get a tag by ID or name" parameters: - name: "id" in: "path" required: true description: "The ID or name of the tag" schema: type: "string" responses: 200: description: "Tag details" content: application/json: schema: $ref: "#/components/schemas/Tag" 404: description: "Tag not found" put: operationId: "updateTag" x-access-level: "member" tags: - "tags" summary: "Update a tag" parameters: - name: "id" in: "path" required: true description: "The ID of the tag to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateTagBody" responses: 204: description: "Tag updated" 403: description: "Access denied" 422: description: "Validation error" delete: operationId: "destroyTag" x-access-level: "bd_staff" tags: - "tags" summary: "Delete a tag" description: "Deletes a tag. The tag must not be present on any post and must have no aliases or implications that are not deleted." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag to delete" schema: type: "integer" responses: 204: description: "The tag was deleted" 302: description: "Redirects back because the tag has posts, aliases or implications" 403: description: "Access denied" 404: description: "Tag not found" /tags/preview.json: post: operationId: "previewTags" x-access-level: "member" tags: - "tags" summary: "Preview tag information" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PreviewTagsBody" responses: 200: description: "Tag preview data" content: application/json: schema: type: "object" /tag_type_versions.json: get: operationId: "searchTagTypeVersions" x-access-level: "anonymous" tags: - "tag_type_versions" summary: "Search tag type change history" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[tag]" in: "query" required: false description: "Filter by tag name" schema: type: "string" - name: "search[user_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[user_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" responses: 200: description: "A list of tag type versions" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/TagTypeVersion" /wiki_pages.json: get: operationId: "searchWikiPages" x-access-level: "anonymous" tags: - "wiki_pages" summary: "Search wiki pages" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[title]" in: "query" required: false description: "Filter by title (supports wildcards)" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Search by body text" schema: type: "string" - name: "search[other_names_match]" in: "query" required: false description: "Search by other names" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[hide_deleted]" in: "query" required: false description: "Hide deleted wiki pages" schema: type: "string" - name: "search[parent]" in: "query" required: false description: "Filter by parent wiki page" schema: type: "string" - name: "search[other_names_present]" in: "query" required: false description: "Filter by whether other names are present" schema: type: "string" - name: "search[is_locked]" in: "query" required: false description: "Filter by locked status" schema: type: "string" - name: "search[is_deleted]" in: "query" required: false description: "Filter by deleted status" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Sort order for results" schema: $ref: "#/components/schemas/SearchWikiPagesSearchOrder" responses: 200: description: "A list of wiki pages" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/WikiPage" post: operationId: "createWikiPage" x-access-level: "member" tags: - "wiki_pages" summary: "Create a wiki page" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWikiPageBody" responses: 201: description: "Wiki page created" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 422: description: "Validation error" /wiki_pages/{id}.json: get: operationId: "getWikiPage" x-access-level: "anonymous" tags: - "wiki_pages" summary: "Get a wiki page by ID or title" parameters: - name: "id" in: "path" required: true description: "The ID or title of the wiki page" schema: type: "string" responses: 200: description: "Wiki page details" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 404: description: "Wiki page not found" put: operationId: "updateWikiPage" x-access-level: "member" tags: - "wiki_pages" summary: "Update a wiki page" parameters: - name: "id" in: "path" required: true description: "The ID of the wiki page to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateWikiPageBody" responses: 204: description: "Wiki page updated" 403: description: "Access denied" 422: description: "Validation error" delete: operationId: "deleteWikiPage" x-access-level: "admin" tags: - "wiki_pages" summary: "Delete a wiki page" parameters: - name: "id" in: "path" required: true description: "The ID of the wiki page to delete" schema: type: "integer" responses: 200: description: "Wiki page deleted" 404: description: "Wiki page not found" /wiki_pages/{id}/revert.json: put: operationId: "revertWikiPage" x-access-level: "member" tags: - "wiki_pages" summary: "Revert a wiki page to a previous version" parameters: - name: "id" in: "path" required: true description: "The ID of the wiki page to revert" schema: type: "integer" - name: "version_id" in: "query" required: true description: "The ID of the version to revert to" schema: type: "integer" responses: 204: description: "Wiki page reverted" 404: description: "Wiki page or version not found" /wiki_pages/show_or_new.json: get: operationId: "showOrNewWikiPage" x-access-level: "anonymous" tags: - "wiki_pages" summary: "Show an existing wiki page or prepare to create a new one" parameters: - name: "title" in: "query" required: false description: "The title to look up or create" schema: type: "string" responses: 200: description: "Wiki page found or new page prepared" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 302: description: "Redirect to existing wiki page" /wiki_page_versions.json: get: operationId: "searchWikiPageVersions" x-access-level: "anonymous" tags: - "wiki_page_versions" summary: "Search wiki page version history" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[updater_id]" in: "query" required: false description: "Filter by updater user ID" schema: type: "integer" - name: "search[updater_name]" in: "query" required: false description: "Filter by updater username" schema: type: "string" - name: "search[wiki_page_id]" in: "query" required: false description: "Filter by wiki page ID" schema: type: "integer" - name: "search[title]" in: "query" required: false description: "Filter by title" schema: type: "string" - name: "search[body]" in: "query" required: false description: "Filter by body text" schema: type: "string" - name: "search[is_locked]" in: "query" required: false description: "Filter by locked status" schema: type: "string" - name: "search[is_deleted]" in: "query" required: false description: "Filter by deleted status" schema: type: "string" responses: 200: description: "A list of wiki page versions" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/WikiPageVersion" /wiki_page_versions/{id}.json: get: operationId: "getWikiPageVersion" x-access-level: "anonymous" tags: - "wiki_page_versions" summary: "Get a wiki page version by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the wiki page version" schema: type: "integer" responses: 200: description: "Wiki page version details" content: application/json: schema: $ref: "#/components/schemas/WikiPageVersion" 404: description: "Wiki page version not found" /wiki_page_versions/diff.json: get: operationId: "diffWikiPageVersions" x-access-level: "anonymous" tags: - "wiki_page_versions" summary: "Diff two wiki page versions" parameters: - name: "thispage" in: "query" required: true description: "The ID of the first wiki page version" schema: type: "integer" - name: "otherpage" in: "query" required: true description: "The ID of the second wiki page version" schema: type: "integer" responses: 200: description: "Diff result between two versions" /notes.json: get: operationId: "searchNotes" x-access-level: "anonymous" tags: - "notes" summary: "Search notes" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[body_matches]" in: "query" required: false description: "Search by note body text" schema: type: "string" - name: "search[is_active]" in: "query" required: false description: "Filter by active status" schema: type: "string" - name: "search[post_id]" in: "query" required: false description: "Filter by post ID (comma-separated for multiple)" schema: type: "string" - name: "search[post_tags_match]" in: "query" required: false description: "Filter by post tags" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" responses: 200: description: "A list of notes" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Note" post: operationId: "createNote" x-access-level: "member" tags: - "notes" summary: "Create a note" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateNoteBody" responses: 201: description: "Note created" content: application/json: schema: type: "object" properties: note: type: "string" description: "JSON-encoded note object" dtext: type: "string" description: "Rendered DText body" 422: description: "Validation error" content: application/json: schema: type: "object" properties: success: type: "boolean" reasons: type: "array" items: type: "string" /notes/{id}.json: get: operationId: "getNote" x-access-level: "anonymous" tags: - "notes" summary: "Get a note by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the note" schema: type: "integer" responses: 200: description: "Note details" content: application/json: schema: $ref: "#/components/schemas/Note" 404: description: "Note not found" put: operationId: "updateNote" x-access-level: "member" tags: - "notes" summary: "Update a note" parameters: - name: "id" in: "path" required: true description: "The ID of the note to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateNoteBody" responses: 200: description: "Note updated" content: application/json: schema: type: "object" properties: note: type: "string" description: "JSON-encoded note object" dtext: type: "string" description: "Rendered DText body" posts: type: "object" description: "Deferred post data" 422: description: "Validation error" content: application/json: schema: type: "object" properties: success: type: "boolean" reasons: type: "array" items: type: "string" delete: operationId: "deleteNote" x-access-level: "member" tags: - "notes" summary: "Delete a note (sets is_active to false)" parameters: - name: "id" in: "path" required: true description: "The ID of the note to delete" schema: type: "integer" responses: 200: description: "Note deleted" 404: description: "Note not found" /notes/{id}/revert.json: put: operationId: "revertNote" x-access-level: "member" tags: - "notes" summary: "Revert a note to a previous version" parameters: - name: "id" in: "path" required: true description: "The ID of the note to revert" schema: type: "integer" - name: "version_id" in: "query" required: true description: "The ID of the version to revert to" schema: type: "integer" responses: 204: description: "Note reverted" 404: description: "Note or version not found" /note_versions.json: get: operationId: "searchNoteVersions" x-access-level: "anonymous" tags: - "note_versions" summary: "Search note version history" parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[updater_id]" in: "query" required: false description: "Filter by updater user ID" schema: type: "integer" - name: "search[updater_name]" in: "query" required: false description: "Filter by updater username" schema: type: "string" - name: "search[post_id]" in: "query" required: false description: "Filter by post ID (comma-separated for multiple)" schema: type: "string" - name: "search[note_id]" in: "query" required: false description: "Filter by note ID (comma-separated for multiple)" schema: type: "string" - name: "search[is_active]" in: "query" required: false description: "Filter by active status" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Search by body text" schema: type: "string" responses: 200: description: "A list of note versions" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/NoteVersion" /pools.json: get: operationId: "searchPools" x-access-level: "anonymous" tags: - "pools" summary: "Search pools" description: "Returns a paginated list of pools matching the given search criteria." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of pools to retrieve per page" schema: type: "integer" - name: "search[name_matches]" in: "query" required: false description: "Filter by pool name (wildcards supported)" schema: type: "string" - name: "search[description_matches]" in: "query" required: false description: "Filter by description text" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[category]" in: "query" required: false description: "Filter by pool category" schema: $ref: "#/components/schemas/PoolCategory" - name: "search[is_active]" in: "query" required: false description: "Filter by active status" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Sort order" schema: $ref: "#/components/schemas/GetArtistsSearchOrder" responses: 200: description: "A list of pools" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Pool" post: operationId: "createPool" x-access-level: "member" tags: - "pools" summary: "Create a new pool" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePoolBody" responses: 201: description: "Pool created" content: application/json: schema: $ref: "#/components/schemas/Pool" 422: description: "Validation error" /pools/{id}.json: get: operationId: "getPool" x-access-level: "anonymous" tags: - "pools" summary: "Get a pool by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the pool" schema: type: "integer" responses: 200: description: "Pool details" content: application/json: schema: $ref: "#/components/schemas/Pool" 404: description: "Pool not found" put: operationId: "updatePool" x-access-level: "member" tags: - "pools" summary: "Update a pool" parameters: - name: "id" in: "path" required: true description: "The ID of the pool to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdatePoolBody" responses: 204: description: "Pool updated" 404: description: "Pool not found" 422: description: "Validation error" delete: operationId: "deletePool" x-access-level: "staff" tags: - "pools" summary: "Delete a pool" parameters: - name: "id" in: "path" required: true description: "The ID of the pool to delete" schema: type: "integer" responses: 200: description: "Pool deleted" 403: description: "Access denied" 404: description: "Pool not found" /pool_versions.json: get: operationId: "searchPoolVersions" x-access-level: "member" tags: - "pools" summary: "Search pool versions" description: "Returns a paginated list of pool version history entries." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of versions to retrieve per page" schema: type: "integer" - name: "search[pool_id]" in: "query" required: false description: "Filter by pool ID" schema: type: "integer" - name: "search[updater_id]" in: "query" required: false description: "Filter by updater user ID" schema: type: "integer" - name: "search[updater_name]" in: "query" required: false description: "Filter by updater username" schema: type: "string" - name: "search[ip_addr]" in: "query" required: false description: "Filter by IP address (admin only)" schema: type: "string" responses: 200: description: "A list of pool versions" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PoolVersion" /pool_element.json: post: operationId: "addPoolElement" x-access-level: "member" tags: - "pools" summary: "Add a post to a pool" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddPoolElementBody" responses: 201: description: "Post added to pool" content: application/json: schema: $ref: "#/components/schemas/Pool" 404: description: "Pool or post not found" 422: description: "Validation error" delete: operationId: "removePoolElement" x-access-level: "member" tags: - "pools" summary: "Remove a post from a pool" parameters: - name: "pool_id" in: "query" required: false description: "The ID of the pool" schema: type: "integer" - name: "pool_name" in: "query" required: false description: "The name of the pool (alternative to pool_id)" schema: type: "string" - name: "post_id" in: "query" required: true description: "The ID of the post to remove" schema: type: "integer" responses: 204: description: "Post removed from pool" 404: description: "Pool or post not found" /pool_element/recent.json: get: operationId: "getRecentPoolElements" x-access-level: "member" tags: - "pools" summary: "Get recently used pools" description: "Returns a list of pools the current user recently added posts to." responses: 200: description: "A list of recent pools" content: application/json: schema: type: "array" items: type: "object" properties: id: type: "integer" description: "The pool ID" name: type: "string" description: "The pool name" /post_sets.json: get: operationId: "searchPostSets" x-access-level: "anonymous" tags: - "post_sets" summary: "Search post sets" description: "Returns a paginated list of post sets matching the given search criteria." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of sets to retrieve per page" schema: type: "integer" - name: "post_id" in: "query" required: false description: "Filter sets containing this post ID" schema: type: "integer" - name: "maintainer_id" in: "query" required: false description: "Filter sets maintained by this user ID" schema: type: "integer" - name: "search[name]" in: "query" required: false description: "Filter by set name (wildcards supported)" schema: type: "string" - name: "search[shortname]" in: "query" required: false description: "Filter by shortname" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Sort order" schema: $ref: "#/components/schemas/SearchPostSetsSearchOrder" responses: 200: description: "A list of post sets" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PostSet" post: operationId: "createPostSet" x-access-level: "member" tags: - "post_sets" summary: "Create a new post set" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePostSetBody" responses: 201: description: "Post set created" content: application/json: schema: $ref: "#/components/schemas/PostSet" 422: description: "Validation error" /post_sets/{id}.json: get: operationId: "getPostSet" x-access-level: "anonymous" tags: - "post_sets" summary: "Get a post set by ID" parameters: - name: "id" in: "path" required: true description: "The ID of the post set" schema: type: "integer" responses: 200: description: "Post set details" content: application/json: schema: $ref: "#/components/schemas/PostSet" 403: description: "Access denied" 404: description: "Post set not found" put: operationId: "updatePostSet" x-access-level: "member" tags: - "post_sets" summary: "Update a post set" parameters: - name: "id" in: "path" required: true description: "The ID of the post set to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdatePostSetBody" responses: 204: description: "Post set updated" 403: description: "Access denied" 422: description: "Validation error" delete: operationId: "deletePostSet" x-access-level: "member" tags: - "post_sets" summary: "Delete a post set" parameters: - name: "id" in: "path" required: true description: "The ID of the post set to delete" schema: type: "integer" responses: 200: description: "Post set deleted" 403: description: "Access denied" 404: description: "Post set not found" /post_sets/for_select.json: get: operationId: "getPostSetsForSelect" x-access-level: "member" tags: - "post_sets" summary: "Get post sets for selection" description: "Returns owned and maintained post sets formatted for use in selection dropdowns." responses: 200: description: "Post sets grouped by ownership" content: application/json: schema: type: "object" properties: Owned: type: "array" items: type: "array" items: oneOf: - type: "string" - type: "integer" Maintained: type: "array" items: type: "array" items: oneOf: - type: "string" - type: "integer" /post_sets/{id}/post_list.json: get: operationId: "getPostSetPostList" x-access-level: "member" tags: - "post_sets" summary: "Get the post list for a post set" parameters: - name: "id" in: "path" required: true description: "The ID of the post set" schema: type: "integer" responses: 200: description: "Post set details with post list" content: application/json: schema: $ref: "#/components/schemas/PostSet" 403: description: "Access denied" 404: description: "Post set not found" /post_sets/{id}/add_posts.json: post: operationId: "addPostSetPosts" x-access-level: "member" tags: - "post_sets" summary: "Add posts to a post set" parameters: - name: "id" in: "path" required: true description: "The ID of the post set" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddPostSetPostsBody" responses: 201: description: "Posts added to set" content: application/json: schema: $ref: "#/components/schemas/PostSet" 403: description: "Access denied" 422: description: "Validation error" /post_sets/{id}/remove_posts.json: post: operationId: "removePostSetPosts" x-access-level: "member" tags: - "post_sets" summary: "Remove posts from a post set" parameters: - name: "id" in: "path" required: true description: "The ID of the post set" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddPostSetPostsBody" responses: 201: description: "Posts removed from set" content: application/json: schema: $ref: "#/components/schemas/PostSet" 403: description: "Access denied" /favorites.json: get: operationId: "getFavorites" x-access-level: "anonymous" tags: - "favorites" summary: "Get a list of favorited posts" description: | Returns a list of posts favorited by the specified user or the current user. Accepts the same `v2` and `mode` parameters as `/posts.json`. parameters: - name: "user_id" in: "query" required: false description: "The user ID whose favorites to retrieve (defaults to current user)" schema: type: "integer" - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of posts to retrieve per page" schema: type: "integer" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" responses: 200: description: "A list of favorited posts" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "posts" description: "Legacy response (default)." properties: posts: type: "array" items: $ref: "#/components/schemas/LegacyPost" - type: "array" x-format: "v2" x-mode: "basic" items: $ref: "#/components/schemas/BasicPost" - type: "array" x-format: "v2" x-mode: "extended" items: $ref: "#/components/schemas/Post" - type: "array" x-format: "v2" x-mode: "thumbnail" items: $ref: "#/components/schemas/ThumbnailPost" post: operationId: "addFavorite" x-access-level: "member" tags: - "favorites" summary: "Favorite a post" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddFavoriteBody" responses: 200: description: "Post favorited" content: application/json: schema: type: "object" properties: post_id: type: "integer" description: "The ID of the favorited post" favorite_count: type: "integer" description: "The new favorite count for the post" 422: description: "Validation error" 423: description: "Favorites are being transferred" /favorites/{id}.json: delete: operationId: "removeFavorite" x-access-level: "member" tags: - "favorites" summary: "Unfavorite a post" parameters: - name: "id" in: "path" required: true description: "The ID of the post to unfavorite" schema: type: "integer" responses: 200: description: "Post unfavorited" content: application/json: schema: type: "object" properties: post_id: type: "integer" description: "The ID of the unfavorited post" favorite_count: type: "integer" description: "The new favorite count for the post" 422: description: "Validation error" 423: description: "Favorites are being transferred" /posts/{post_id}/favorites.json: get: operationId: "getPostFavorites" x-access-level: "anonymous" tags: - "favorites" summary: "Get users who favorited a post" description: "Returns a paginated list of users who favorited the specified post." parameters: - name: "post_id" in: "path" required: true description: "The ID of the post" schema: type: "integer" - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of users to retrieve per page (max 100)" schema: type: "integer" responses: 200: description: "A list of users who favorited the post" content: application/json: schema: type: "array" items: type: "object" properties: id: type: "integer" description: "The user ID" name: type: "string" description: "The username" 403: description: "Access denied when the post has `hide_favorites_list` enabled and the caller is not staff" 404: description: "Post not found" /post_votes.json: get: operationId: "getPostVotes" x-access-level: "moderator" tags: - "post_votes" summary: "Get a list of post votes" description: "Returns a paginated list of post votes based on search criteria." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of post votes to retrieve per page" schema: type: "integer" - name: "search[post_id]" in: "query" required: false description: "Filter by post ID" schema: type: "integer" - name: "search[user_name]" in: "query" required: false description: "Filter by voter username" schema: type: "string" - name: "search[user_id]" in: "query" required: false description: "Filter by voter user ID" schema: type: "integer" - name: "search[post_creator_id]" in: "query" required: false description: "Filter by post uploader ID" schema: type: "integer" - name: "search[post_creator_name]" in: "query" required: false description: "Filter by post uploader username" schema: type: "string" - name: "search[timeframe]" in: "query" required: false description: "Filter by votes within the last N days" schema: type: "integer" - name: "search[score]" in: "query" required: false description: "Filter by vote score (1 or -1)" schema: $ref: "#/components/schemas/CreatePostVoteBodyScore" - name: "search[user_ip_addr]" in: "query" required: false description: "Filter by voter IP address (admin only)" schema: type: "string" - name: "search[duplicates_only]" in: "query" required: false description: "Show only duplicate IP votes (admin only)" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Sort order (admin only, supports ip_addr)" schema: type: "string" responses: 200: description: "A list of post votes" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PostVote" 403: description: "Access denied" /post_votes/lock.json: post: operationId: "lockPostVotes" x-access-level: "moderator" tags: - "post_votes" summary: "Lock post votes" description: "Locks the specified post votes, preventing further voting changes." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LockPostVotesBody" responses: 200: description: "Votes locked" 403: description: "Access denied" /post_votes/delete.json: post: operationId: "deletePostVotes" x-access-level: "admin" tags: - "post_votes" summary: "Delete post votes" description: "Deletes the specified post votes." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LockPostVotesBody" responses: 200: description: "Votes deleted" 403: description: "Access denied" /posts/{post_id}/votes.json: post: operationId: "createPostVote" x-access-level: "member" tags: - "post_votes" summary: "Vote on a post" description: "Casts a vote on the specified post. Voting again with the same score will remove the vote unless no_unvote is set." parameters: - name: "post_id" in: "path" required: true description: "The ID of the post to vote on" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePostVoteBody" responses: 200: description: "Vote cast successfully" content: application/json: schema: type: "object" properties: score: type: "integer" description: "The new total score of the post" up: type: "integer" description: "The new upvote score of the post" down: type: "integer" description: "The new downvote score of the post" our_score: type: "integer" description: "The current user's vote score (0 if unvoted)" 422: description: "Validation error" delete: operationId: "deletePostVote" x-access-level: "member" tags: - "post_votes" summary: "Remove vote from a post" description: "Removes the current user's vote from the specified post." parameters: - name: "post_id" in: "path" required: true description: "The ID of the post to remove the vote from" schema: type: "integer" responses: 200: description: "Vote removed" 422: description: "Validation error" /post_flags/{id}/clear_note.json: post: operationId: "clearPostFlagNote" x-access-level: "janitor" tags: - "post_flags" summary: "Clear a post flag note" description: "Removes the note from the specified post flag." parameters: - name: "id" in: "path" required: true description: "The ID of the post flag" schema: type: "integer" responses: 201: description: "Note cleared" content: application/json: schema: $ref: "#/components/schemas/PostFlag" 404: description: "Post flag not found" /posts/{post_id}/flag.json: delete: operationId: "resolvePostFlag" x-access-level: "janitor" tags: - "post_flags" summary: "Resolve a post flag" description: "Resolves the active flag on a post, optionally approving the post." parameters: - name: "post_id" in: "path" required: true description: "The ID of the flagged post" schema: type: "integer" - name: "approval" in: "query" required: false description: "Set to \"approve\" to also approve the post" schema: $ref: "#/components/schemas/ResolvePostFlagApproval" responses: 200: description: "Post flag resolved" 404: description: "Post not found" /staff/post/approval.json: post: operationId: "approvePost" x-access-level: "approver" tags: - "staff" summary: "Approve a post" description: "Approves a pending post for publication." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddFavoriteBody" responses: 201: description: "Post approved" 403: description: "Cannot approve this post" delete: operationId: "unapprovePost" x-access-level: "approver" tags: - "staff" summary: "Unapprove a post" description: "Removes approval from a post." parameters: - name: "post_id" in: "query" required: true description: "The ID of the post to unapprove" schema: type: "integer" responses: 200: description: "Post unapproved" 403: description: "Cannot unapprove this post" /staff/post/disapprovals.json: get: operationId: "getPostDisapprovals" x-access-level: "approver" tags: - "staff" summary: "Get a list of post disapprovals" description: "Returns a paginated list of post disapprovals." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of disapprovals to retrieve per page" schema: type: "integer" - name: "search[post_id]" in: "query" required: false description: "Filter by post ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by disapprover username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by disapprover user ID" schema: type: "integer" - name: "search[reason]" in: "query" required: false description: "Filter by reason (borderline_quality, borderline_relevancy, other)" schema: $ref: "#/components/schemas/PostDisapprovalReason" - name: "search[message]" in: "query" required: false description: "Filter by message text" schema: type: "string" - name: "search[post_tags_match]" in: "query" required: false description: "Filter by post tags" schema: type: "string" - name: "search[has_message]" in: "query" required: false description: "Filter by presence of message" schema: type: "boolean" responses: 200: description: "A list of post disapprovals" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PostDisapproval" 403: description: "Access denied" post: operationId: "createPostDisapproval" x-access-level: "approver" tags: - "staff" summary: "Create a post disapproval" description: "Disapproves a post with a reason and optional message." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePostDisapprovalBody" responses: 201: description: "Post disapproval created" content: application/json: schema: $ref: "#/components/schemas/PostDisapproval" 422: description: "Validation error" /staff/post/posts/{id}/delete.json: post: operationId: "staffDeletePost" x-access-level: "approver" tags: - "staff" summary: "Delete a post" description: "Deletes a post with a reason. Can optionally copy sources, tags, or move favorites to a parent post." parameters: - name: "id" in: "path" required: true description: "The ID of the post to delete" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/StaffDeletePostBody" responses: 200: description: "Post deleted" content: application/json: schema: $ref: "#/components/schemas/LegacyPost" 422: description: "Validation error" /staff/post/posts/{id}/undelete.json: post: operationId: "staffUndeletePost" x-access-level: "approver" tags: - "staff" summary: "Undelete a post" description: "Restores a previously deleted post." parameters: - name: "id" in: "path" required: true description: "The ID of the post to undelete" schema: type: "integer" responses: 201: description: "Post undeleted" content: application/json: schema: $ref: "#/components/schemas/LegacyPost" 404: description: "Post not found" /staff/post/posts/{id}/expunge.json: post: operationId: "staffExpungePost" x-access-level: "admin" tags: - "staff" summary: "Expunge a post" description: "Permanently removes a post and its files from the system." parameters: - name: "id" in: "path" required: true description: "The ID of the post to expunge" schema: type: "integer" requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/StaffExpungePostBody" responses: 201: description: "Post expunged" content: application/json: schema: $ref: "#/components/schemas/LegacyPost" 404: description: "Post not found" /staff/post/posts/{id}/move_favorites.json: post: operationId: "staffMoveFavorites" x-access-level: "approver" tags: - "staff" summary: "Move favorites to parent post" description: "Transfers favorites and post sets from this post to its parent post." parameters: - name: "id" in: "path" required: true description: "The ID of the post to move favorites from" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/StaffMoveFavoritesBody" responses: 302: description: "Redirects to the post page after moving favorites" /staff/post/posts/{id}/regenerate_thumbnails.json: post: operationId: "staffRegenerateThumbnails" x-access-level: "janitor" tags: - "staff" summary: "Regenerate post thumbnails" description: "Regenerates the image samples and thumbnails for a post." parameters: - name: "id" in: "path" required: true description: "The ID of the post to regenerate thumbnails for" schema: type: "integer" responses: 201: description: "Thumbnails regenerated" content: application/json: schema: $ref: "#/components/schemas/LegacyPost" 404: description: "Post not found" /staff/post/posts/{id}/regenerate_videos.json: post: operationId: "staffRegenerateVideos" x-access-level: "janitor" tags: - "staff" summary: "Regenerate post video samples" description: "Regenerates the video samples for a post. Cannot be used on deleted posts." parameters: - name: "id" in: "path" required: true description: "The ID of the post to regenerate video samples for" schema: type: "integer" responses: 201: description: "Video samples regenerated" content: application/json: schema: $ref: "#/components/schemas/LegacyPost" 403: description: "Cannot regenerate thumbnails on deleted images" 404: description: "Post not found" /staff/ip_addrs.json: get: operationId: "getModeratorIpAddrs" x-access-level: "admin" tags: - "staff" summary: "Search IP address usage" description: "Searches for IP address usage across the site by user ID, username, or IP address." parameters: - name: "search[user_id]" in: "query" required: false description: "Filter by user ID (comma-separated for multiple)" schema: type: "string" - name: "search[user_name]" in: "query" required: false description: "Filter by username (comma-separated for multiple)" schema: type: "string" - name: "search[ip_addr]" in: "query" required: false description: "Filter by IP address (comma-separated for multiple, supports CIDR notation)" schema: type: "string" - name: "search[add_ip_mask]" in: "query" required: false description: "Automatically add a /24 (IPv4) or /64 (IPv6) mask to a single IP address" schema: type: "boolean" responses: 200: description: "IP address search results" content: application/json: schema: type: "object" properties: sums: type: "object" description: "Activity counts grouped by type and user/IP" users: type: "object" description: "User objects keyed by user ID" 403: description: "Access denied" /staff/ip_addrs/export.json: get: operationId: "exportModeratorIpAddrs" x-access-level: "admin" tags: - "staff" summary: "Export IP address data" description: "Exports IP address data with full history included." parameters: - name: "search[user_id]" in: "query" required: false description: "Filter by user ID (comma-separated for multiple)" schema: type: "string" - name: "search[user_name]" in: "query" required: false description: "Filter by username (comma-separated for multiple)" schema: type: "string" - name: "search[ip_addr]" in: "query" required: false description: "Filter by IP address (comma-separated for multiple, supports CIDR notation)" schema: type: "string" - name: "search[add_ip_mask]" in: "query" required: false description: "Automatically add a /24 (IPv4) or /64 (IPv6) mask to a single IP address" schema: type: "boolean" responses: 200: description: "Exported IP address data" content: application/json: schema: type: "array" items: type: "string" description: "Unique IP addresses" 403: description: "Access denied" /avoid_postings.json: get: operationId: "getAvoidPostings" x-access-level: "anonymous" tags: - "avoid_postings" summary: "Get a list of avoid posting entries" description: "Returns a list of avoid posting (Do Not Post) entries." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of entries to retrieve per page" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by the creator's username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by the creator's user ID" schema: type: "integer" - name: "search[artist_name]" in: "query" required: false description: "Filter by exact artist name" schema: type: "string" - name: "search[artist_id]" in: "query" required: false description: "Filter by artist ID" schema: type: "integer" - name: "search[any_name_matches]" in: "query" required: false description: "Filter by partial name match (searches name, other names, and group name)" schema: type: "string" - name: "search[any_other_name_matches]" in: "query" required: false description: "Filter by other name match" schema: type: "string" - name: "search[group_name]" in: "query" required: false description: "Filter by group name" schema: type: "string" - name: "search[details]" in: "query" required: false description: "Filter by details text" schema: type: "string" - name: "search[is_active]" in: "query" required: false description: "Filter by active status" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Order the results" schema: $ref: "#/components/schemas/GetAvoidPostingsSearchOrder" responses: 200: description: "A list of avoid posting entries" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/AvoidPosting" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createAvoidPosting" x-access-level: "bd_staff" tags: - "avoid_postings" summary: "Create an avoid posting entry" description: "Creates a new avoid posting (Do Not Post) entry." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateAvoidPostingBody" responses: 201: description: "The created avoid posting entry" content: application/json: schema: $ref: "#/components/schemas/AvoidPosting" 422: description: "Validation error" 403: description: "Access denied" /avoid_postings/{id}.json: get: operationId: "getAvoidPosting" x-access-level: "anonymous" tags: - "avoid_postings" summary: "Get an avoid posting entry by ID or name" description: "Returns detailed information about a specific avoid posting entry. The ID can be a numeric ID or an artist name." parameters: - name: "id" in: "path" required: true description: "The ID or artist name of the avoid posting entry" schema: type: "string" responses: 200: description: "Successful response containing avoid posting details" content: application/json: schema: $ref: "#/components/schemas/AvoidPosting" 404: description: "Avoid posting entry not found" 500: description: "Server error" put: operationId: "updateAvoidPosting" x-access-level: "bd_staff" tags: - "avoid_postings" summary: "Update an avoid posting entry" description: "Updates an existing avoid posting entry." parameters: - name: "id" in: "path" required: true description: "The ID or artist name of the avoid posting entry" schema: type: "string" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateAvoidPostingBody" responses: 204: description: "The updated avoid posting entry" 422: description: "Validation error" 403: description: "Access denied" delete: operationId: "destroyAvoidPosting" x-access-level: "bd_staff" tags: - "avoid_postings" summary: "Destroy an avoid posting entry" description: "Permanently destroys an avoid posting entry and redirects to the artist it belonged to." parameters: - name: "id" in: "path" required: true description: "The ID or artist name of the avoid posting entry" schema: type: "string" responses: 302: description: "Redirects to the artist after destroying the entry" 403: description: "Access denied" 404: description: "Avoid posting entry not found" /avoid_postings/{id}/delete.json: put: operationId: "deleteAvoidPosting" x-access-level: "bd_staff" tags: - "avoid_postings" summary: "Soft-delete an avoid posting entry" description: "Marks an avoid posting entry as inactive (soft delete)." parameters: - name: "id" in: "path" required: true description: "The ID or artist name of the avoid posting entry" schema: type: "string" responses: 302: description: "Redirects back after soft-deleting" 403: description: "Access denied" /avoid_postings/{id}/undelete.json: put: operationId: "undeleteAvoidPosting" x-access-level: "bd_staff" tags: - "avoid_postings" summary: "Undelete an avoid posting entry" description: "Restores a soft-deleted avoid posting entry to active status." parameters: - name: "id" in: "path" required: true description: "The ID or artist name of the avoid posting entry" schema: type: "string" responses: 302: description: "Redirects back after undeleting" 403: description: "Access denied" /avoid_posting_versions.json: get: operationId: "getAvoidPostingVersions" x-access-level: "anonymous" tags: - "avoid_postings" summary: "Get a list of avoid posting versions" description: "Returns a list of avoid posting version history entries." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of versions to retrieve per page" schema: type: "integer" - name: "search[updater_name]" in: "query" required: false description: "Filter by updater username" schema: type: "string" - name: "search[updater_id]" in: "query" required: false description: "Filter by updater user ID" schema: type: "integer" - name: "search[artist_name]" in: "query" required: false description: "Filter by artist name" schema: type: "string" - name: "search[artist_id]" in: "query" required: false description: "Filter by artist ID" schema: type: "integer" - name: "search[any_name_matches]" in: "query" required: false description: "Filter by partial name match" schema: type: "string" - name: "search[any_other_name_matches]" in: "query" required: false description: "Filter by other name match" schema: type: "string" - name: "search[group_name]" in: "query" required: false description: "Filter by group name" schema: type: "string" - name: "search[is_active]" in: "query" required: false description: "Filter by active status" schema: type: "boolean" responses: 200: description: "A list of avoid posting versions" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/AvoidPostingVersion" 400: description: "Invalid request parameters" 500: description: "Server error" /takedowns.json: get: operationId: "getTakedowns" x-access-level: "anonymous" tags: - "takedowns" summary: "Get a list of takedowns" description: "Returns a list of takedown requests. Most fields are hidden from non-staff users." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of takedowns to retrieve per page" schema: type: "integer" - name: "search[status]" in: "query" required: false description: "Filter by takedown status" schema: $ref: "#/components/schemas/TakedownStatus" - name: "search[source]" in: "query" required: false description: "Filter by source (moderator only)" schema: type: "string" - name: "search[reason]" in: "query" required: false description: "Filter by reason (moderator only)" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username (moderator only)" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID (moderator only)" schema: type: "integer" - name: "search[post_id]" in: "query" required: false description: "Filter by post ID (moderator only)" schema: type: "integer" - name: "search[notes]" in: "query" required: false description: "Filter by notes (moderator only)" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Order the results (admin only)" schema: $ref: "#/components/schemas/GetTakedownsSearchOrder" responses: 200: description: "A list of takedown requests" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Takedown" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createTakedown" x-access-level: "anonymous" tags: - "takedowns" summary: "Create a takedown" description: "Creates a takedown request and redirects to it with its verification code attached. Rejected while takedowns are disabled by site lockdown." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateTakedownBody" responses: 302: description: "Redirects to the created takedown with its verification code" 400: description: "The takedown parameter is missing" 403: description: "Takedowns are disabled, or a supplied attribute is not permitted at this user level" 422: description: "Validation error" /takedowns/{id}.json: get: operationId: "getTakedown" x-access-level: "anonymous" tags: - "takedowns" summary: "Get a takedown by ID" description: "Returns detailed information about a specific takedown request." parameters: - name: "id" in: "path" required: true description: "The unique ID of the takedown" schema: type: "integer" - name: "code" in: "query" required: false description: "Verification code to view takedown instructions" schema: type: "string" responses: 200: description: "Successful response containing takedown details" content: application/json: schema: $ref: "#/components/schemas/Takedown" 404: description: "Takedown not found" 500: description: "Server error" put: operationId: "updateTakedown" x-access-level: "bd_staff" tags: - "takedowns" summary: "Update a takedown" description: "Updates a takedown request. Can also process the takedown." parameters: - name: "id" in: "path" required: true description: "The unique ID of the takedown" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateTakedownBody" responses: 204: description: "The updated takedown" 422: description: "Validation error" 403: description: "Access denied" delete: operationId: "destroyTakedown" x-access-level: "bd_staff" tags: - "takedowns" summary: "Destroy a takedown" description: "Permanently destroys a takedown request." parameters: - name: "id" in: "path" required: true description: "The unique ID of the takedown" schema: type: "integer" responses: 204: description: "The takedown was destroyed" 403: description: "Access denied" 404: description: "Takedown not found" /takedowns/count_matching_posts.json: post: operationId: "countMatchingTakedownPosts" x-access-level: "bd_staff" tags: - "takedowns" summary: "Count posts matching a tag query" description: "Returns the count of posts matching the given tag query. Used when adding posts to a takedown by tags." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddTakedownPostsByTagsBody" responses: 200: description: "The count of matching posts" content: application/json: schema: type: "object" properties: matched_post_count: type: "integer" description: "The number of posts matching the tag query" 403: description: "Access denied" /takedowns/{id}/add_by_ids.json: post: operationId: "addTakedownPostsByIds" x-access-level: "bd_staff" tags: - "takedowns" summary: "Add posts to a takedown by IDs" description: "Adds posts to a takedown request using post IDs." parameters: - name: "id" in: "path" required: true description: "The unique ID of the takedown" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddTakedownPostsByIdsBody" responses: 201: description: "Posts added successfully" content: application/json: schema: type: "object" properties: added_count: type: "integer" description: "Number of posts added" added_post_ids: type: "array" items: type: "integer" description: "IDs of posts that were added" 403: description: "Access denied" /takedowns/{id}/add_by_tags.json: post: operationId: "addTakedownPostsByTags" x-access-level: "bd_staff" tags: - "takedowns" summary: "Add posts to a takedown by tags" description: "Adds posts to a takedown request using a tag query." parameters: - name: "id" in: "path" required: true description: "The unique ID of the takedown" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddTakedownPostsByTagsBody" responses: 201: description: "Posts added successfully" content: application/json: schema: type: "object" properties: added_count: type: "integer" description: "Number of posts added" added_post_ids: type: "array" items: type: "integer" description: "IDs of posts that were added" 403: description: "Access denied" /takedowns/{id}/remove_by_ids.json: post: operationId: "removeTakedownPostsByIds" x-access-level: "bd_staff" tags: - "takedowns" summary: "Remove posts from a takedown by IDs" description: "Removes posts from a takedown request using post IDs." parameters: - name: "id" in: "path" required: true description: "The unique ID of the takedown" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddTakedownPostsByIdsBody" responses: 200: description: "Posts removed successfully" 403: description: "Access denied" /ip_bans.json: get: operationId: "getIpBans" x-access-level: "admin" tags: - "ip_bans" summary: "Get a list of IP bans" description: "Returns a list of IP bans." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of IP bans to retrieve per page" schema: type: "integer" - name: "search[ip_addr]" in: "query" required: false description: "Filter by IP address" schema: type: "string" - name: "search[banner_id]" in: "query" required: false description: "Filter by banning staff user ID" schema: type: "integer" - name: "search[banner_name]" in: "query" required: false description: "Filter by banning staff username" schema: type: "string" - name: "search[reason]" in: "query" required: false description: "Filter by ban reason" schema: type: "string" responses: 200: description: "A list of IP bans" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/IpBan" 403: description: "Access denied" 500: description: "Server error" post: operationId: "createIpBan" x-access-level: "admin" tags: - "ip_bans" summary: "Create an IP ban" description: "Creates a new IP ban." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateIpBanBody" responses: 201: description: "The created IP ban" content: application/json: schema: $ref: "#/components/schemas/IpBan" 422: description: "Validation error" 403: description: "Access denied" /ip_bans/{id}.json: delete: operationId: "destroyIpBan" x-access-level: "admin" tags: - "ip_bans" summary: "Destroy an IP ban" description: "Removes an IP ban." parameters: - name: "id" in: "path" required: true description: "The unique ID of the IP ban" schema: type: "integer" responses: 204: description: "The IP ban was destroyed" 403: description: "Access denied" 404: description: "IP ban not found" /artist_versions.json: get: operationId: "getArtistVersions" x-access-level: "anonymous" tags: - "artists" summary: "Get a list of artist versions" description: "Returns a list of artist version history entries." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of versions to retrieve per page" schema: type: "integer" - name: "search[name]" in: "query" required: false description: "Filter by artist name" schema: type: "string" - name: "search[updater_name]" in: "query" required: false description: "Filter by updater username" schema: type: "string" - name: "search[updater_id]" in: "query" required: false description: "Filter by updater user ID" schema: type: "integer" - name: "search[artist_id]" in: "query" required: false description: "Filter by artist ID" schema: type: "integer" - name: "search[is_active]" in: "query" required: false description: "Filter by active status" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Order the results" schema: $ref: "#/components/schemas/GetArtistVersionsSearchOrder" responses: 200: description: "A list of artist versions" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ArtistVersion" 400: description: "Invalid request parameters" 500: description: "Server error" /artist_urls.json: get: operationId: "getArtistUrls" x-access-level: "anonymous" tags: - "artists" summary: "Get a list of artist URLs" description: "Returns a list of artist URLs with their associated artist information." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of URLs to retrieve per page" schema: type: "integer" - name: "search[artist_id]" in: "query" required: false description: "Filter by artist ID" schema: type: "integer" - name: "search[artist_name]" in: "query" required: false description: "Filter by artist name" schema: type: "string" - name: "search[is_active]" in: "query" required: false description: "Filter by active status" schema: type: "boolean" - name: "search[url]" in: "query" required: false description: "Filter by URL" schema: type: "string" - name: "search[url_matches]" in: "query" required: false description: "Filter by URL match (wildcards supported)" schema: type: "string" - name: "search[normalized_url]" in: "query" required: false description: "Filter by normalized URL" schema: type: "string" - name: "search[normalized_url_matches]" in: "query" required: false description: "Filter by normalized URL match (wildcards supported)" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Order the results" schema: type: "string" responses: 200: description: "A list of artist URLs" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ArtistUrl" 400: description: "Invalid request parameters" 500: description: "Server error" /upload_whitelists.json: get: operationId: "getUploadWhitelists" x-access-level: "anonymous" tags: - "upload_whitelists" summary: "Get a list of upload whitelist entries" description: "Returns a list of upload whitelist entries." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of entries to retrieve per page" schema: type: "integer" - name: "search[allowed]" in: "query" required: false description: "Filter by allowed status" schema: type: "boolean" - name: "search[domain]" in: "query" required: false description: "Filter by domain" schema: type: "string" - name: "search[path]" in: "query" required: false description: "Filter by path" schema: type: "string" - name: "search[note]" in: "query" required: false description: "Filter by note" schema: type: "string" - name: "search[reason]" in: "query" required: false description: "Filter by reason" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Order the results" schema: $ref: "#/components/schemas/GetUploadWhitelistsSearchOrder" responses: 200: description: "A list of upload whitelist entries" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/UploadWhitelist" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createUploadWhitelist" x-access-level: "admin" tags: - "upload_whitelists" summary: "Create an upload whitelist entry" description: "Creates a new upload whitelist entry." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateUploadWhitelistBody" responses: 201: description: "The created upload whitelist entry" content: application/json: schema: $ref: "#/components/schemas/UploadWhitelist" 422: description: "Validation error" 403: description: "Access denied" /upload_whitelists/{id}.json: delete: operationId: "destroyUploadWhitelist" x-access-level: "admin" tags: - "upload_whitelists" summary: "Destroy an upload whitelist entry" description: "Removes an upload whitelist entry." parameters: - name: "id" in: "path" required: true description: "The unique ID of the whitelist entry" schema: type: "integer" responses: 204: description: "The whitelist entry was destroyed" 403: description: "Access denied" 404: description: "Whitelist entry not found" put: operationId: "updateUploadWhitelist" x-access-level: "admin" tags: - "upload_whitelists" summary: "Update an upload whitelist entry" description: "Updates an upload whitelist entry, then redirects to the index. Returns no body." parameters: - name: "id" in: "path" required: true description: "The unique ID of the whitelist entry" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateUploadWhitelistBody" responses: 302: description: "Redirects to the whitelist index" 403: description: "Access denied" 404: description: "Whitelist entry not found" /upload_whitelists/is_allowed.json: get: operationId: "isUploadUrlAllowed" x-access-level: "anonymous" tags: - "upload_whitelists" summary: "Check if a URL is allowed for upload" description: "Checks if a given URL is whitelisted for upload." parameters: - name: "url" in: "query" required: true description: "The URL to check" schema: type: "string" responses: 200: description: "The whitelist check result" content: application/json: schema: type: "object" properties: url: type: "string" description: "The URL that was checked" domain: type: "string" description: "The domain of the URL" is_allowed: type: "boolean" description: "Whether the URL is allowed" reason: type: "string" description: "The reason for the result" /popular.json: get: operationId: "getPopularPosts" x-access-level: "anonymous" tags: - "posts" summary: "Get popular posts" description: | Returns a list of popular posts for a given date and time scale. Accepts the same `v2` and `mode` parameters as `/posts.json`. parameters: - name: "date" in: "query" required: false description: "The date to get popular posts for (YYYY-MM-DD format)" schema: type: "string" format: "date" - name: "scale" in: "query" required: false description: "The time scale for popularity" schema: $ref: "#/components/schemas/GetPopularPostsScale" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" responses: 200: description: "A list of popular posts" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "posts" description: "Legacy response (default)." properties: posts: type: "array" items: $ref: "#/components/schemas/LegacyPost" - type: "array" x-format: "v2" x-mode: "basic" items: $ref: "#/components/schemas/BasicPost" - type: "array" x-format: "v2" x-mode: "extended" items: $ref: "#/components/schemas/Post" - type: "array" x-format: "v2" x-mode: "thumbnail" items: $ref: "#/components/schemas/ThumbnailPost" 422: description: "Invalid parameters" 500: description: "Server error" /iqdb_queries.json: get: operationId: "getIqdbQuery" x-access-level: "anonymous" tags: - "iqdb" summary: "Search for similar images (GET)" description: "Queries the IQDB service for visually similar images using a post ID, URL, or hash." parameters: - name: "search[post_id]" in: "query" required: false description: "Find images similar to this post" schema: type: "integer" - name: "search[url]" in: "query" required: false description: "Find images similar to the image at this URL" schema: type: "string" - name: "search[hash]" in: "query" required: false description: "Find images similar to this perceptual hash" schema: type: "string" - name: "search[score_cutoff]" in: "query" required: false description: "Minimum similarity score threshold" schema: type: "number" - name: "v2" in: "query" required: false description: "If `\"true\"`, the `post` field uses the basic v2 Post format instead of the legacy serialization." schema: $ref: "#/components/schemas/GetIqdbQueryV2" responses: 200: description: "A list of similar image matches" content: application/json: schema: type: "object" properties: posts: type: "array" items: $ref: "#/components/schemas/IqdbQuery" 404: description: "File not found or too large" 500: description: "IQDB service error" post: operationId: "postIqdbQuery" x-access-level: "anonymous" tags: - "iqdb" summary: "Search for similar images (POST)" description: "Queries the IQDB service for visually similar images. Accepts a file upload, a URL, or a post ID." parameters: - name: "v2" in: "query" required: false description: "If `\"true\"`, the `post` field uses the basic v2 Post format instead of the legacy serialization." schema: $ref: "#/components/schemas/GetIqdbQueryV2" requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/PostIqdbQueryBody" responses: 200: description: "A list of similar image matches" content: application/json: schema: type: "object" properties: posts: type: "array" items: $ref: "#/components/schemas/IqdbQuery" 404: description: "File not found or too large" 500: description: "IQDB service error" /related_tag.json: get: operationId: "getRelatedTag" x-access-level: "member" tags: - "tags" summary: "Get related tags" description: "Returns tags related to the given query tag." parameters: - name: "search[query]" in: "query" required: true description: "The tag to find related tags for" schema: type: "string" - name: "search[category_id]" in: "query" required: false description: "Filter by tag category ID" schema: type: "integer" responses: 200: description: "Related tags for the query" content: application/json: schema: $ref: "#/components/schemas/RelatedTag" 403: description: "Access denied" /related_tag/bulk.json: get: operationId: "getRelatedTagBulk" x-access-level: "member" tags: - "tags" summary: "Get related tags in bulk" description: "Returns related tags for a bulk query." parameters: - name: "query" in: "query" required: true description: "The tag query for bulk related tag lookup" schema: type: "string" - name: "category_id" in: "query" required: false description: "Filter by tag category ID" schema: type: "integer" responses: 200: description: "Bulk related tag results" content: application/json: schema: $ref: "#/components/schemas/RelatedTag" 403: description: "Access denied" post: operationId: "postRelatedTagBulk" x-access-level: "member" tags: - "tags" summary: "Get related tags in bulk (POST)" description: "Returns related tags for a bulk query via POST." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PostRelatedTagBulkBody" responses: 201: description: "Bulk related tag results" content: application/json: schema: $ref: "#/components/schemas/RelatedTag" 403: description: "Access denied" /dtext_preview.json: post: operationId: "createDtextPreview" x-access-level: "anonymous" tags: - "utilities" summary: "Preview DText formatting" description: "Renders DText markup into HTML." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateDtextPreviewBody" responses: 200: description: "The rendered DText preview" content: application/json: schema: type: "object" properties: html: type: "string" description: "The rendered HTML" posts: type: "object" description: "Deferred post data referenced in the DText" /mascots.json: get: operationId: "getMascots" x-access-level: "anonymous" tags: - "mascots" summary: "Get a list of mascots" description: "Returns a list of site mascots." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of mascots to retrieve per page" schema: type: "integer" responses: 200: description: "A list of mascots" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Mascot" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createMascot" x-access-level: "admin" tags: - "mascots" summary: "Create a mascot" description: "Creates a new site mascot." requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/CreateMascotBody" responses: 201: description: "The created mascot" content: application/json: schema: $ref: "#/components/schemas/Mascot" 422: description: "Validation error" 403: description: "Access denied" /mascots/{id}.json: put: operationId: "updateMascot" x-access-level: "admin" tags: - "mascots" summary: "Update a mascot" description: "Updates an existing mascot." parameters: - name: "id" in: "path" required: true description: "The unique ID of the mascot" schema: type: "integer" requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/UpdateMascotBody" responses: 204: description: "The updated mascot" 422: description: "Validation error" 403: description: "Access denied" delete: operationId: "destroyMascot" x-access-level: "admin" tags: - "mascots" summary: "Destroy a mascot" description: "Permanently removes a mascot." parameters: - name: "id" in: "path" required: true description: "The unique ID of the mascot" schema: type: "integer" responses: 204: description: "The mascot was destroyed" 403: description: "Access denied" 404: description: "Mascot not found" /help.json: get: operationId: "getHelpPages" x-access-level: "anonymous" tags: - "help_pages" summary: "Get a list of help pages" description: "Returns a list of all help pages sorted by title." responses: 200: description: "A list of help pages" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/HelpPage" 500: description: "Server error" post: operationId: "createHelpPage" x-access-level: "admin" tags: - "help_pages" summary: "Create a help page" description: "Creates a new help page." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateHelpPageBody" responses: 201: description: "The created help page" content: application/json: schema: $ref: "#/components/schemas/HelpPage" 422: description: "Validation error" 403: description: "Access denied" /help/{id}.json: get: operationId: "getHelpPage" x-access-level: "anonymous" tags: - "help_pages" summary: "Get a help page by ID or name" description: "Returns detailed information about a specific help page." parameters: - name: "id" in: "path" required: true description: "The ID or name of the help page" schema: type: "string" responses: 200: description: "Successful response containing help page details" content: application/json: schema: $ref: "#/components/schemas/HelpPage" 404: description: "Help page not found" 500: description: "Server error" put: operationId: "updateHelpPage" x-access-level: "admin" tags: - "help_pages" summary: "Update a help page" description: "Updates an existing help page." parameters: - name: "id" in: "path" required: true description: "The ID of the help page" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateHelpPageBody" responses: 204: description: "The updated help page" 422: description: "Validation error" 403: description: "Access denied" delete: operationId: "destroyHelpPage" x-access-level: "admin" tags: - "help_pages" summary: "Destroy a help page" description: "Permanently removes a help page." parameters: - name: "id" in: "path" required: true description: "The ID of the help page" schema: type: "integer" responses: 204: description: "The help page was destroyed" 403: description: "Access denied" 404: description: "Help page not found" /news_updates.json: get: operationId: "getNewsUpdates" x-access-level: "anonymous" tags: - "news_updates" summary: "Get a list of news updates" description: "Returns a list of news updates ordered by most recent first." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of news updates to retrieve per page" schema: type: "integer" responses: 200: description: "A list of news updates" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/NewsUpdate" 400: description: "Invalid request parameters" 500: description: "Server error" /email_blacklists.json: get: operationId: "getEmailBlacklists" x-access-level: "admin" tags: - "email_blacklists" summary: "Get a list of email blacklist entries" description: "Returns a list of blacklisted email domains." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of entries to retrieve per page" schema: type: "integer" - name: "search[domain]" in: "query" required: false description: "Filter by domain" schema: type: "string" - name: "search[reason]" in: "query" required: false description: "Filter by reason" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Order the results" schema: $ref: "#/components/schemas/GetEmailBlacklistsSearchOrder" responses: 200: description: "A list of email blacklist entries" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/EmailBlacklist" 403: description: "Access denied" 500: description: "Server error" post: operationId: "createEmailBlacklist" x-access-level: "admin" tags: - "email_blacklists" summary: "Create an email blacklist entry" description: "Creates a new email blacklist entry." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateEmailBlacklistBody" responses: 201: description: "The created email blacklist entry" content: application/json: schema: $ref: "#/components/schemas/EmailBlacklist" 422: description: "Validation error" 403: description: "Access denied" /email_blacklists/{id}.json: delete: operationId: "destroyEmailBlacklist" x-access-level: "admin" tags: - "email_blacklists" summary: "Destroy an email blacklist entry" description: "Removes an email blacklist entry." parameters: - name: "id" in: "path" required: true description: "The unique ID of the blacklist entry" schema: type: "integer" responses: 204: description: "The blacklist entry was destroyed" 403: description: "Access denied" 404: description: "Blacklist entry not found" /.well-known/openid-configuration: get: operationId: "getOpenidConfiguration" x-access-level: "anonymous" tags: - "oauth" summary: "Get the OpenID Connect provider metadata" description: | Returns the OpenID Connect discovery document. Served by doorkeeper-openid_connect. Null members are omitted from the response. responses: 200: description: "The provider metadata document" content: application/json: schema: $ref: "#/components/schemas/OpenidConfiguration" /.well-known/oauth-authorization-server: get: operationId: "getOauthAuthorizationServer" x-access-level: "anonymous" tags: - "oauth" summary: "Get the OAuth authorization server metadata" description: "Returns the same document as `/.well-known/openid-configuration`." responses: 200: description: "The authorization server metadata document" content: application/json: schema: $ref: "#/components/schemas/OpenidConfiguration" /.well-known/webfinger: get: operationId: "getWebfinger" x-access-level: "anonymous" tags: - "oauth" summary: "Resolve an issuer via WebFinger" description: "Returns the OpenID Connect issuer for the requested resource." parameters: - name: "resource" in: "query" required: true description: "The resource to resolve. Required." schema: type: "string" responses: 200: description: "The WebFinger document" content: application/json: schema: $ref: "#/components/schemas/Webfinger" /oauth/discovery/keys: get: operationId: "getOauthKeys" x-access-level: "anonymous" tags: - "oauth" summary: "Get the JSON Web Key Set" description: "Returns the public keys used to verify ID token signatures." responses: 200: description: "The JWKS document" content: application/json: schema: $ref: "#/components/schemas/Jwks" /oauth/userinfo: get: operationId: "getOauthUserinfo" x-access-level: "logged_in" tags: - "oauth" summary: "Get claims about the authenticated user" description: | Returns the OpenID Connect claims for the user who owns the bearer token. Which claims are present depends on the scopes granted to the token. responses: 200: description: "The claims for the authenticated user" content: application/json: schema: $ref: "#/components/schemas/Userinfo" 401: description: "Missing or invalid bearer token" post: operationId: "postOauthUserinfo" x-access-level: "logged_in" tags: - "oauth" summary: "Get claims about the authenticated user" description: "Identical to the GET form, for clients that send the bearer token in the body." responses: 200: description: "The claims for the authenticated user" content: application/json: schema: $ref: "#/components/schemas/Userinfo" 401: description: "Missing or invalid bearer token" /oauth/token: post: operationId: "createOauthToken" x-access-level: "anonymous" tags: - "oauth" summary: "Exchange an authorization code or refresh token for an access token" description: | The only grant flow enabled is `authorization_code`, and PKCE is required with the `S256` challenge method. Refresh tokens are issued. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateOauthTokenBody" responses: 200: description: "The issued token" content: application/json: schema: $ref: "#/components/schemas/OauthToken" 400: description: "Invalid request" 401: description: "Invalid client credentials" /oauth/revoke: post: operationId: "revokeOauthToken" x-access-level: "anonymous" tags: - "oauth" summary: "Revoke an access or refresh token" description: "Revokes the supplied token. Returns an empty object even when the token was already invalid." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/RevokeOauthTokenBody" responses: 200: description: "The token was revoked, or was already invalid" /oauth/introspect: post: operationId: "introspectOauthToken" x-access-level: "anonymous" tags: - "oauth" summary: "Introspect a token" description: "Returns the state of the supplied token." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/IntrospectOauthTokenBody" responses: 200: description: "The token state" content: application/json: schema: $ref: "#/components/schemas/OauthTokenIntrospection" /oauth/token/info: get: operationId: "getOauthTokenInfo" x-access-level: "logged_in" tags: - "oauth" summary: "Get information about the current access token" description: "Returns the attributes of the bearer token used to make the request." responses: 200: description: "The token attributes" content: application/json: schema: $ref: "#/components/schemas/OauthTokenInfo" 401: description: "Missing or invalid bearer token" /db_exports.json: get: operationId: "getDbExports" x-access-level: "anonymous" tags: - "db_exports" summary: "Get the list of database exports" description: | Returns the available database export files. Responds 404 when database exports are disabled for the site. responses: 200: description: "The available database exports" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/DbExport" 404: description: "Database exports are disabled" /users/new.json: get: operationId: "getNewUser" x-access-level: "anonymous" tags: - "users" summary: "Get a blank user record for signup" description: "Returns an unsaved, blank user record used to prime a signup form. Only available while logged out and when signups are enabled." responses: 200: description: "A blank user record" content: application/json: schema: $ref: "#/components/schemas/User" 403: description: "Already signed in, or signups are disabled" /users/{id}/edit.json: get: operationId: "getEditUser" x-access-level: "logged_in" tags: - "users" summary: "Get the current user's editable account record" description: "Returns the authenticated user's own account record. The `id` in the path is ignored: the action always loads the current user." parameters: - name: "id" in: "path" required: true description: "Ignored by the server; the current user is always returned" schema: type: "string" responses: 200: description: "The current user's account record" content: application/json: schema: $ref: "#/components/schemas/User" 403: description: "Not logged in" /users/avatar_menu.json: get: operationId: "getUserAvatarMenu" x-access-level: "logged_in" tags: - "users" summary: "Get the current user's avatar menu flags" description: "Returns booleans telling the avatar dropdown which of the current user's content listings are non-empty." responses: 200: description: "Avatar menu flags" content: application/json: schema: $ref: "#/components/schemas/UserAvatarMenu" 403: description: "Not logged in" /users/upload_tags.json: get: operationId: "getUserUploadTags" x-access-level: "logged_in" tags: - "users" summary: "Get the current user's upload tag suggestions" description: "Returns the current user's favorite tags and the tags they most recently added to posts, for the upload tag editor." responses: 200: description: "Upload tag suggestions" content: application/json: schema: $ref: "#/components/schemas/UserUploadTags" 403: description: "Not logged in" /users/{id}/toggle_uploads.json: get: operationId: "toggleUserUploads" x-access-level: "janitor" tags: - "users" summary: "Toggle a user's ability to upload" description: | Flips a user's upload ban. If the user's uploads are currently enabled, disabling them requires a reason, so the action returns the user record instead of acting; submit the reason to `/users/{id}/disable_uploads.json`. If the user's uploads are currently disabled, they are re-enabled and the response is a redirect. parameters: - name: "id" in: "path" required: true description: "The ID or username of the user" schema: type: "string" responses: 200: description: "The user whose uploads are about to be disabled" content: application/json: schema: $ref: "#/components/schemas/User" 302: description: "Uploads were re-enabled; redirect to the user's profile" 403: description: "Access denied" 404: description: "User not found" /users/{id}/disable_uploads.json: post: operationId: "disableUserUploads" x-access-level: "janitor" tags: - "users" summary: "Disable a user's ability to upload" description: "Bans a user from uploading and records the supplied reason as a staff note. The reason is mandatory." parameters: - name: "id" in: "path" required: true description: "The ID or username of the user" schema: type: "string" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateStaffNoteBody" responses: 302: description: "Redirect to the user's profile; the outcome is carried in the flash message" 403: description: "Access denied" 404: description: "User not found" /users/{id}/toggle_karma_free.json: get: operationId: "toggleUserKarmaFree" x-access-level: "janitor" tags: - "users" summary: "Toggle a user's unlimited uploads" description: | Flips a user's karma-free upload ban. If the user's unlimited uploads are currently enabled, disabling them requires a reason, so the action returns the user record instead of acting; submit the reason to `/users/{id}/disable_karma_free.json`. If they are currently disabled, they are re-enabled and the response is a redirect. A user below the karma threshold is redirected without any change. parameters: - name: "id" in: "path" required: true description: "The ID or username of the user" schema: type: "string" responses: 200: description: "The user whose unlimited uploads are about to be disabled" content: application/json: schema: $ref: "#/components/schemas/User" 302: description: "Unlimited uploads were re-enabled, or the user is not eligible; redirect to the user's profile" 403: description: "Access denied" 404: description: "User not found" /users/{id}/disable_karma_free.json: post: operationId: "disableUserKarmaFree" x-access-level: "janitor" tags: - "users" summary: "Disable a user's unlimited uploads" description: "Revokes a user's karma-free upload bypass and records the supplied reason as a staff note. The reason is mandatory." parameters: - name: "id" in: "path" required: true description: "The ID or username of the user" schema: type: "string" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateStaffNoteBody" responses: 302: description: "Redirect to the user's profile; the outcome is carried in the flash message" 403: description: "Access denied" 404: description: "User not found" /users/{id}/flush_favorites.json: post: operationId: "flushUserFavorites" x-access-level: "admin" tags: - "users" summary: "Flush a user's favorites" description: "Enqueues a background job that removes every favorite belonging to the user." parameters: - name: "id" in: "path" required: true description: "The ID or username of the user" schema: type: "string" responses: 302: description: "Redirect to the user's profile" 403: description: "Access denied" 404: description: "User not found" /users/{id}/fix_counts.json: get: operationId: "fixUserCounts" x-access-level: "janitor" tags: - "users" summary: "Recount a user's cached statistics" description: "Recomputes the user's cached post, comment, note and other counters." parameters: - name: "id" in: "path" required: true description: "The ID or username of the user" schema: type: "string" responses: 302: description: "Redirect to the user's profile" 403: description: "Access denied" 404: description: "User not found" /staff/users/alt_list.json: get: operationId: "getStaffUserAltList" x-access-level: "admin" tags: - "staff" summary: "List users sharing a last-seen IP address" description: | Returns 250 users per page, newest first, each paired with the IDs of other accounts that share their last-seen IP address and logged in within the last three months. Each entry is a two-element array: the user's ID, then the array of suspected alt IDs. parameters: - name: "page" in: "query" required: false description: "The page number to retrieve; clamped to 1-10000" schema: type: "integer" responses: 200: description: "Pairs of user ID and suspected alt IDs" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/StaffUserAltListEntry" 403: description: "Access denied" /staff/users/{id}.json: put: operationId: "updateStaffUser" x-access-level: "admin" tags: - "staff" summary: "Edit a user as staff" description: | Updates another user's profile, upload limit, level, flags and karma. `email` is only accepted from BD staff, and `verified` is only honoured for BD staff. Changing `level` runs the promotion checks: BD staff cannot be demoted by non-BD staff, and only BD staff may promote to admin. Supplying a `name` different from the current one files an administrative name change request. parameters: - name: "id" in: "path" required: true description: "The unique ID of the user to edit" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateStaffUserBody" responses: 302: description: "Redirect to the user's profile" 403: description: "Access denied" 404: description: "User not found" /staff/users/{id}/update_blacklist.json: post: operationId: "updateStaffUserBlacklist" x-access-level: "admin" tags: - "staff" summary: "Replace a user's blacklist" description: "Overwrites another user's blacklisted tags. Logged as a mod action unless staff are editing their own blacklist." parameters: - name: "id" in: "path" required: true description: "The unique ID of the user" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateStaffUserBlacklistBody" responses: 302: description: "Redirect to the blacklist edit page" 403: description: "Access denied" 404: description: "User not found" /staff/users/{id}/totp_reset.json: post: operationId: "resetStaffUserTotp" x-access-level: "admin" tags: - "staff" summary: "Remove two-factor authentication from a user" description: | Clears a user's TOTP enrolment and emails them about it. Only BD staff may do this to a staff account. Requires the session to have been re-authenticated within the last hour. parameters: - name: "id" in: "path" required: true description: "The unique ID of the user" schema: type: "integer" responses: 302: description: "Redirect to the user's profile, or to the re-authentication page" 403: description: "Access denied" 404: description: "User not found" /staff/users/{id}/anonymize.json: post: operationId: "anonymizeStaffUser" x-access-level: "admin" tags: - "staff" summary: "Delete a user account" description: | Anonymizes a user, renaming the account, wiping its settings and password, and flushing its favorites. Requires admin level plus the BD staff flag, and a session re-authenticated within the last hour. Staff accounts and already-deleted accounts are rejected. parameters: - name: "id" in: "path" required: true description: "The unique ID of the user to delete" schema: type: "integer" requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/AnonymizeStaffUserBody" responses: 302: description: "Redirect to the user's profile, or to the re-authentication page" 403: description: "Access denied" 404: description: "User not found" /staff/users/{user_id}/dmails.json: get: operationId: "getStaffUserDmails" x-access-level: "bd_auditor" tags: - "staff" summary: "List a user's DMails" description: "Returns the DMails owned by an arbitrary user. Restricted to accounts carrying the BD auditor flag." parameters: - name: "user_id" in: "path" required: true description: "The unique ID of the user whose DMails to list" schema: type: "integer" - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of DMails to retrieve per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by DMail ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by last update date" schema: type: "string" - name: "search[title_matches]" in: "query" required: false description: "Filter by title text" schema: type: "string" - name: "search[message_matches]" in: "query" required: false description: "Filter by message body text" schema: type: "string" - name: "search[to_name]" in: "query" required: false description: "Filter by recipient username" schema: type: "string" - name: "search[to_id]" in: "query" required: false description: "Filter by recipient user ID" schema: type: "integer" - name: "search[from_name]" in: "query" required: false description: "Filter by sender username" schema: type: "string" - name: "search[from_id]" in: "query" required: false description: "Filter by sender user ID" schema: type: "integer" - name: "search[is_read]" in: "query" required: false description: "Filter by read status" schema: type: "boolean" - name: "search[is_deleted]" in: "query" required: false description: "Filter by deleted status" schema: type: "boolean" - name: "search[read]" in: "query" required: false description: "Restrict to read DMails when true, or to unread and undeleted DMails when false" schema: type: "boolean" responses: 200: description: "A list of the user's DMails" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Dmail" 403: description: "Access denied" 404: description: "User not found" /staff/users/{user_id}/dmails/{id}.json: get: operationId: "getStaffUserDmail" x-access-level: "bd_auditor" tags: - "staff" summary: "Get one of a user's DMails" description: "Returns a single DMail. Restricted to accounts carrying the BD auditor flag." parameters: - name: "user_id" in: "path" required: true description: "The unique ID of the user the DMail is looked up under" schema: type: "integer" - name: "id" in: "path" required: true description: "The unique ID of the DMail" schema: type: "integer" responses: 200: description: "DMail details" content: application/json: schema: $ref: "#/components/schemas/Dmail" 403: description: "Access denied" 404: description: "User or DMail not found" /staff/user_alts.json: get: operationId: "getUserAlts" x-access-level: "moderator" tags: - "staff" summary: "Find a user's suspected alt accounts" description: | Ranks candidate alt accounts for a user by shared-network evidence, highest score first. The response carries scores and IP-derived evidence only; no IP or subnet value is ever exposed. parameters: - name: "user_id" in: "query" required: true description: "The unique ID of the user to analyse" schema: type: "integer" responses: 200: description: "Ranked alt account candidates" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/UserAlt" 403: description: "Access denied" 404: description: "User not found" /staff_notes/new.json: get: operationId: "getNewStaffNote" x-access-level: "staff" tags: - "staff_notes" summary: "Get a blank staff note" description: "Primes a staff note form for a user. The response body is always the JSON literal `null`, because the action builds the note into one variable and responds with another that is never assigned." parameters: - name: "user_id" in: "query" required: true description: "The ID of the user the note would be about" schema: type: "integer" - name: "staff_note[body]" in: "query" required: false description: "Prefills the note body" schema: type: "string" responses: 200: description: "Always the JSON literal `null`" 403: description: "Access denied" 404: description: "User not found" /staff_notes/{id}/edit.json: get: operationId: "getEditStaffNote" x-access-level: "staff" tags: - "staff_notes" summary: "Get a staff note for editing" description: "Returns the staff note to be edited." parameters: - name: "id" in: "path" required: true description: "The ID of the staff note" schema: type: "integer" responses: 200: description: "Staff note details" content: application/json: schema: $ref: "#/components/schemas/StaffNote" 403: description: "Access denied" 404: description: "Staff note not found" /staff_notes/{id}/delete.json: put: operationId: "deleteStaffNote" x-access-level: "staff" tags: - "staff_notes" summary: "Soft-delete a staff note" description: "Marks a staff note as deleted without removing it. Only the note's creator or an admin may do this." parameters: - name: "id" in: "path" required: true description: "The ID of the staff note" schema: type: "integer" responses: 302: description: "Redirect back to the referring page, or to the staff note index" 403: description: "Access denied" 404: description: "Staff note not found" /staff_notes/{id}/undelete.json: put: operationId: "undeleteStaffNote" x-access-level: "staff" tags: - "staff_notes" summary: "Undelete a staff note" description: "Restores a soft-deleted staff note. Only the note's creator or an admin may do this." parameters: - name: "id" in: "path" required: true description: "The ID of the staff note" schema: type: "integer" responses: 302: description: "Redirect back to the referring page, or to the staff note index" 403: description: "Access denied" 404: description: "Staff note not found" /user_feedbacks/new.json: get: operationId: "getNewUserFeedback" x-access-level: "moderator" tags: - "user_feedbacks" summary: "Get a blank user feedback" description: "Returns an unsaved user feedback, prefilled from any supplied query parameters." parameters: - name: "user_feedback[user_id]" in: "query" required: false description: "Prefills the subject user ID" schema: type: "integer" - name: "user_feedback[user_name]" in: "query" required: false description: "Prefills the subject username" schema: type: "string" - name: "user_feedback[body]" in: "query" required: false description: "Prefills the feedback body" schema: type: "string" - name: "user_feedback[category]" in: "query" required: false description: "Prefills the feedback category" schema: $ref: "#/components/schemas/UserFeedbackCategory" responses: 200: description: "A blank user feedback" content: application/json: schema: $ref: "#/components/schemas/UserFeedback" 403: description: "Access denied" /user_feedbacks/{id}/edit.json: get: operationId: "getEditUserFeedback" x-access-level: "moderator" tags: - "user_feedbacks" summary: "Get a user feedback for editing" description: "Returns the feedback to be edited. Moderators cannot edit feedback left about themselves." parameters: - name: "id" in: "path" required: true description: "The unique ID of the user feedback" schema: type: "integer" responses: 200: description: "User feedback details" content: application/json: schema: $ref: "#/components/schemas/UserFeedback" 403: description: "Not authorized to edit this feedback" 404: description: "User feedback not found" /user_name_change_requests/new.json: get: operationId: "getNewUserNameChangeRequest" x-access-level: "member" tags: - "user_name_change_requests" summary: "Get a blank name change request" description: "Returns an unsaved name change request, prefilled from any supplied query parameters." parameters: - name: "user_name_change_request[desired_name]" in: "query" required: false description: "Prefills the desired username" schema: type: "string" - name: "user_name_change_request[change_reason]" in: "query" required: false description: "Prefills the reason for the change" schema: type: "string" responses: 200: description: "A blank name change request" content: application/json: schema: $ref: "#/components/schemas/UserNameChangeRequest" 403: description: "Access denied" /api_keys/new.json: get: operationId: "getNewApiKey" x-access-level: "member" tags: - "api_keys" summary: "Get a blank API key" description: | Returns an unsaved API key bound to the current user, used to prime the creation form. The endpoint rejects both API key and bearer token authentication, so it is reachable only with a browser session, and that session must have been re-authenticated within the last hour. responses: 200: description: "A blank API key" content: application/json: schema: $ref: "#/components/schemas/ApiKey" 302: description: "Redirect to the re-authentication page" 403: description: "Access denied, or the request used API key or bearer authentication" /maintenance/user/dmail_filter.json: put: operationId: "updateDmailFilter" x-access-level: "logged_in" tags: - "dmails" summary: "Update the current user's DMail filter" description: | Replaces the current user's DMail filter word list. The route is nested under a DMail, so `dmail_id` is required and must name a DMail the current user owns, even though the filter itself is not attached to it. parameters: - name: "dmail_id" in: "query" required: true description: "The ID of a DMail owned by the current user" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateDmailFilterBody" responses: 204: description: "Filter updated" 400: description: "The `dmail_filter` parameter is missing" 403: description: "The DMail is not owned by the current user" 404: description: "DMail not found" /posts/random.json: get: operationId: "getRandomPost" x-access-level: "anonymous" tags: - "posts" summary: "Get a random post" description: | Returns a single random post matching the `tags` search. When `v2=true`, the response uses the v2 Post format selected by `mode` (`basic` default, `extended`, or `thumbnail`). Otherwise the legacy format wrapped in `{ "post": {...} }` is returned. parameters: - name: "tags" in: "query" required: false description: "Restrict the random pick to posts matching these tags" schema: type: "string" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" responses: 200: description: "Successful response containing a random post" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "post" description: "Legacy response (default, or when `v2` is not \"true\"). The post is wrapped under `post`." properties: post: $ref: "#/components/schemas/LegacyPost" - $ref: "#/components/schemas/BasicPost" x-format: "v2" x-mode: "basic" - $ref: "#/components/schemas/Post" x-format: "v2" x-mode: "extended" - $ref: "#/components/schemas/ThumbnailPost" x-format: "v2" x-mode: "thumbnail" 404: description: "No post matched the tags" 500: description: "Server error" /posts/count.json: get: operationId: "getPostCount" x-access-level: "anonymous" tags: - "posts" summary: "Count posts matching a tag search" description: "Returns an approximate number of posts matching the search. The count is capped. `capped` reports whether the cap was hit." parameters: - name: "tags" in: "query" required: false description: "The tag search to count. Defaults to an empty search." schema: type: "string" responses: 200: description: "The approximate post count" content: application/json: schema: $ref: "#/components/schemas/PostCount" 400: description: "Invalid tags parameter" 422: description: "The tag search was rejected (too many tags, too complex, or invalid)" /posts/{id}/update_iqdb.json: get: operationId: "updatePostIqdb" x-access-level: "admin" tags: - "posts" summary: "Queue an IQDB reindex for a post" description: | Enqueues an asynchronous IQDB reindex of the post and returns the post. When `v2=true`, the response uses the v2 Post format selected by `mode` (`basic` default, `extended`, or `thumbnail`). Otherwise the legacy format wrapped in `{ "post": {...} }` is returned. parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to reindex" schema: type: "integer" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" responses: 200: description: "The post whose reindex was queued" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "post" description: "Legacy response (default, or when `v2` is not \"true\"). The post is wrapped under `post`." properties: post: $ref: "#/components/schemas/LegacyPost" - $ref: "#/components/schemas/BasicPost" x-format: "v2" x-mode: "basic" - $ref: "#/components/schemas/Post" x-format: "v2" x-mode: "extended" - $ref: "#/components/schemas/ThumbnailPost" x-format: "v2" x-mode: "thumbnail" 403: description: "Access denied" 404: description: "Post not found" /posts/{id}/revert.json: put: operationId: "revertPost" x-access-level: "member" tags: - "posts" summary: "Revert a post to a previous version" description: "Reverts the post's tags, rating, parent, source, and description to the given version. Returns no body." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to revert" schema: type: "integer" - name: "version_id" in: "query" required: true description: "The ID of the post version to revert to" schema: type: "integer" responses: 204: description: "Post reverted" 403: description: "Access denied or the edit throttle was hit" 404: description: "Post or version not found" /posts/{id}/copy_notes.json: put: operationId: "copyPostNotes" x-access-level: "member" tags: - "posts" summary: "Copy notes from one post to another" description: "Copies every note on this post onto another post. Returns no body on success." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to copy notes from" schema: type: "integer" - name: "other_post_id" in: "query" required: true description: "The ID of the post to copy the notes onto" schema: type: "integer" responses: 204: description: "Notes copied" 400: description: "The notes could not be copied" content: application/json: schema: type: "object" properties: success: type: "boolean" reason: type: "string" 403: description: "Access denied or the edit throttle was hit" 404: description: "Post not found" /posts/{id}/show_seq.json: get: operationId: "getPostInSequence" x-access-level: "anonymous" tags: - "posts" summary: "Get the next or previous post in a search" description: | Returns the post that comes after (or before, with `seq=prev`) the given post within the supplied tag search. Falls back to the given post itself when the search yields nothing. When `v2=true`, the response uses the v2 Post format selected by `mode` (`basic` default, `extended`, or `thumbnail`). Otherwise the legacy format wrapped in `{ "post": {...} }` is returned. parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to move away from" schema: type: "integer" - name: "seq" in: "query" required: false description: "Direction to move in the sequence. `prev` moves backwards. Any other value moves forwards." schema: type: "string" - name: "q" in: "query" required: false description: "The tag search the sequence is taken from. Takes precedence over `tags`." schema: type: "string" - name: "tags" in: "query" required: false description: "The tag search the sequence is taken from. Used when `q` is absent." schema: type: "string" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" responses: 200: description: "Successful response containing the neighbouring post" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "post" description: "Legacy response (default, or when `v2` is not \"true\"). The post is wrapped under `post`." properties: post: $ref: "#/components/schemas/LegacyPost" - $ref: "#/components/schemas/BasicPost" x-format: "v2" x-mode: "basic" - $ref: "#/components/schemas/Post" x-format: "v2" x-mode: "extended" - $ref: "#/components/schemas/ThumbnailPost" x-format: "v2" x-mode: "thumbnail" 403: description: "The post is not visible under the current lockdown" 404: description: "Post not found" /posts/{id}/mark_as_translated.json: put: operationId: "markPostAsTranslated" x-access-level: "member" tags: - "posts" summary: "Mark a post as translated" description: | Adds or removes the `translation_check` and `partially_translated` tags, then sets either `translated` or `translation_request` to match. When `v2=true`, the response uses the v2 Post format selected by `mode` (`basic` default, `extended`, or `thumbnail`). Otherwise the legacy format wrapped in `{ "post": {...} }` is returned. parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to mark" schema: type: "integer" - $ref: "#/components/parameters/PostV2Flag" - $ref: "#/components/parameters/PostV2Mode" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MarkPostAsTranslatedBody" responses: 200: description: "The post after the translation tags were applied" content: application/json: schema: oneOf: - type: "object" x-format: "legacy" x-wrapper: "post" description: "Legacy response (default, or when `v2` is not \"true\"). The post is wrapped under `post`." properties: post: $ref: "#/components/schemas/LegacyPost" - $ref: "#/components/schemas/BasicPost" x-format: "v2" x-mode: "basic" - $ref: "#/components/schemas/Post" x-format: "v2" x-mode: "extended" - $ref: "#/components/schemas/ThumbnailPost" x-format: "v2" x-mode: "thumbnail" 403: description: "Access denied or the edit throttle was hit" 404: description: "Post not found" /posts/{id}/similar/artist.json: get: operationId: "getSimilarPostsByArtist" x-access-level: "anonymous" tags: - "posts" summary: "Get posts recommended by artist" description: "Returns posts recommended for this post based on its artist tags. Results are cached for six hours." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to find recommendations for" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of recommendations to return. Clamped to 1-20. Defaults to 6." schema: type: "integer" responses: 200: description: "The recommended posts" content: application/json: schema: $ref: "#/components/schemas/PostRecommendations" 404: description: "Post not found" /posts/{id}/similar/tags.json: get: operationId: "getSimilarPostsByTags" x-access-level: "anonymous" tags: - "posts" summary: "Get posts recommended by tags" description: "Returns posts recommended for this post based on its tags. Results are cached for six hours." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post to find recommendations for" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of recommendations to return. Clamped to 1-20. Defaults to 6." schema: type: "integer" responses: 200: description: "The recommended posts" content: application/json: schema: $ref: "#/components/schemas/PostRecommendations" 404: description: "Post not found" /post_replacements/new.json: get: operationId: "getNewPostReplacement" x-access-level: "member" tags: - "post_replacements" summary: "Get a blank post replacement" description: "Returns an unsaved post replacement attached to the given post. Requires membership of the replacements beta." parameters: - name: "post_id" in: "query" required: true description: "The ID of the post the replacement would apply to" schema: type: "integer" responses: 200: description: "A blank post replacement" content: application/json: schema: $ref: "#/components/schemas/PostReplacement" 403: description: "Access denied, or replacements are disabled" 404: description: "Post not found" /post_replacements/{id}/transfer.json: put: operationId: "transferPostReplacement" x-access-level: "approver" tags: - "post_replacements" summary: "Transfer a post replacement to another post" description: "Moves a pending or rejected replacement onto a different post. Returns no body on success." parameters: - name: "id" in: "path" required: true description: "The unique ID of the post replacement" schema: type: "integer" - name: "new_post_id" in: "query" required: true description: "The ID of the post to move the replacement onto" schema: type: "integer" responses: 204: description: "Replacement transferred" 403: description: "Access denied" 404: description: "Post replacement or destination post not found" 412: description: "The transfer was refused" content: application/json: schema: type: "object" properties: success: type: "boolean" message: type: "string" /posts/{post_id}/replacements.json: get: operationId: "getPostReplacementsForPost" x-access-level: "anonymous" tags: - "post_replacements" summary: "Get the replacements for a post" description: "Returns the post replacements belonging to a single post." parameters: - name: "post_id" in: "path" required: true description: "The ID of the post whose replacements to list" schema: type: "integer" - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of replacements to retrieve per page" schema: type: "integer" - name: "search[md5]" in: "query" required: false description: "Filter replacements by the MD5 hash of the file" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter replacements by the creator's username" schema: type: "string" - name: "search[approver_name]" in: "query" required: false description: "Filter replacements by the approver's username" schema: type: "string" - name: "search[uploader_name_on_approve]" in: "query" required: false description: "Filter replacements by the uploader's username at approval time" schema: type: "string" - name: "search[status]" in: "query" required: false description: "Filter replacements by status" schema: $ref: "#/components/schemas/GetPostReplacementsSearchStatus" - name: "search[created_at]" in: "query" required: false description: "Filter replacements by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter replacements by last update date" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter replacements by replacement ID" schema: type: "string" responses: 200: description: "A list of the post's replacements" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/PostReplacement" 400: description: "Invalid request parameters" 500: description: "Server error" post: operationId: "createPostReplacementForPost" x-access-level: "member" tags: - "post_replacements" summary: "Create a replacement for a post" description: "Creates a new post replacement for the post named in the path. Requires membership of the replacements beta. The `post_id` field of the body is ignored in favour of the path segment." parameters: - name: "post_id" in: "path" required: true description: "The ID of the post to replace" schema: type: "integer" requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/CreatePostReplacementBody" responses: 200: description: "The replacement was submitted" content: application/json: schema: type: "object" properties: success: type: "boolean" location: type: "string" 403: description: "Access denied, or replacements are disabled" 404: description: "Post not found" 412: description: "Replacement validation failed" content: application/json: schema: type: "object" properties: success: type: "boolean" message: type: "string" /posts/{post_id}/replacements/new.json: get: operationId: "getNewPostReplacementForPost" x-access-level: "member" tags: - "post_replacements" summary: "Get a blank replacement for a post" description: "Returns an unsaved post replacement attached to the post named in the path. Requires membership of the replacements beta." parameters: - name: "post_id" in: "path" required: true description: "The ID of the post the replacement would apply to" schema: type: "integer" responses: 200: description: "A blank post replacement" content: application/json: schema: $ref: "#/components/schemas/PostReplacement" 403: description: "Access denied, or replacements are disabled" 404: description: "Post not found" /staff/post/posts/{id}/ai_check.json: get: operationId: "staffAiCheckPost" x-access-level: "janitor" tags: - "staff" summary: "Run an AI content check on a post" description: "Runs the AI content detector against the post, then redirects back. Also requires Janitor+. Also requires `is_approver?`." parameters: - name: "id" in: "path" required: true description: "The ID of the post to check" schema: type: "integer" responses: 302: description: "Redirects back after running the check" 403: description: "Access denied" 404: description: "Post not found" /staff/post/posts/{id}/previous_owners.json: get: operationId: "staffGetPostPreviousOwners" x-access-level: "approver" tags: - "staff" summary: "Get a post's previous uploaders" description: "Returns the users who have previously owned the post, taken from its version history." parameters: - name: "id" in: "path" required: true description: "The ID of the post" schema: type: "integer" responses: 200: description: "The post's previous owners" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/StaffPostPreviousOwner" 403: description: "Access denied" 404: description: "Post not found" /staff/post/posts/{id}/reowner.json: post: operationId: "staffReownerPost" x-access-level: "janitor" tags: - "staff" summary: "Reassign a post's uploader" description: "Transfers ownership of the post to another user, optionally moving its versions, post events, and upload karma. Also requires Janitor+. Also requires `is_approver?`." parameters: - name: "id" in: "path" required: true description: "The ID of the post to reassign" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/StaffReownerPostBody" responses: 201: description: "The post after reassignment" content: application/json: schema: $ref: "#/components/schemas/LegacyPost" 204: description: "The new owner could not be found, so nothing changed" 403: description: "Access denied" 404: description: "Post not found" /post_sets/{id}/edit.json: get: operationId: "getEditPostSet" x-access-level: "member" tags: - "post_sets" summary: "Get a post set for editing" description: "Returns a post set, restricted to requesters who may edit its posts." parameters: - name: "id" in: "path" required: true description: "The ID of the post set" schema: type: "integer" responses: 200: description: "The post set" content: application/json: schema: $ref: "#/components/schemas/PostSet" 403: description: "Access denied" 404: description: "Post set not found" /post_sets/{id}/update_posts.json: post: operationId: "updatePostSetPosts" x-access-level: "member" tags: - "post_sets" summary: "Replace the posts in a post set" description: "Replaces the set's contents with the post IDs parsed out of `post_set[post_ids_string]`, adding and removing as needed, then redirects. Returns no body." parameters: - name: "id" in: "path" required: true description: "The ID of the post set" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdatePostSetPostsBody" responses: 302: description: "Redirects to the set's post list after the update" 403: description: "Access denied" 404: description: "Post set not found" 429: description: "Too many set modifications; wait and retry" /uploads/new.json: get: operationId: "getNewUpload" x-access-level: "member" tags: - "uploads" summary: "Get a blank upload" description: "Returns an unsaved upload. Rejected while uploads are locked down, for accounts below the upload minimum level, and during an account's first week." responses: 200: description: "A blank upload" content: application/json: schema: $ref: "#/components/schemas/Upload" 403: description: "Access denied, or uploads are disabled" /post_flags/new.json: get: operationId: "getNewPostFlag" x-access-level: "member" tags: - "post_flags" summary: "Get a blank post flag" description: "Returns an unsaved post flag pre-filled from the supplied fields." parameters: - name: "post_flag[post_id]" in: "query" required: true description: "The ID of the post the flag would apply to" schema: type: "integer" - name: "post_flag[reason_name]" in: "query" required: false description: "The name of the flag reason" schema: type: "string" - name: "post_flag[parent_id]" in: "query" required: false description: "The parent post ID, for inferior duplicates" schema: type: "integer" - name: "post_flag[note]" in: "query" required: false description: "Additional explanation for the flag" schema: type: "string" responses: 200: description: "A blank post flag" content: application/json: schema: $ref: "#/components/schemas/PostFlag" 403: description: "Access denied" 404: description: "Post not found" /pools/new.json: get: operationId: "getNewPool" x-access-level: "member" tags: - "pools" summary: "Get a blank pool" description: "Returns an unsaved pool." responses: 200: description: "A blank pool" content: application/json: schema: $ref: "#/components/schemas/Pool" 403: description: "Access denied, or pools are locked down" /pools/{id}/edit.json: get: operationId: "getEditPool" x-access-level: "member" tags: - "pools" summary: "Get a pool for editing" description: "Returns a pool." parameters: - name: "id" in: "path" required: true description: "The ID of the pool" schema: type: "integer" responses: 200: description: "The pool" content: application/json: schema: $ref: "#/components/schemas/Pool" 403: description: "Access denied, or pools are locked down" 404: description: "Pool not found" /pools/{id}/revert.json: put: operationId: "revertPool" x-access-level: "member" tags: - "pools" summary: "Revert a pool to a previous version" description: "Reverts the pool's name, description, category, and post order to the given version. Returns no body." parameters: - name: "id" in: "path" required: true description: "The ID of the pool to revert" schema: type: "integer" - name: "version_id" in: "query" required: true description: "The ID of the pool version to revert to" schema: type: "integer" responses: 204: description: "Pool reverted" 403: description: "Access denied, or pools are locked down" 404: description: "Pool or version not found" /pools/{pool_id}/order/edit.json: get: operationId: "getEditPoolOrder" x-access-level: "member" tags: - "pools" summary: "Get a pool for post reordering" description: "Returns the pool whose post order is being edited." parameters: - name: "pool_id" in: "path" required: true description: "The ID of the pool" schema: type: "integer" responses: 200: description: "The pool" content: application/json: schema: $ref: "#/components/schemas/Pool" 403: description: "Access denied" 404: description: "Pool not found" /upload_whitelists/{id}/edit.json: get: operationId: "getEditUploadWhitelist" x-access-level: "admin" tags: - "upload_whitelists" summary: "Get an upload whitelist entry for editing" description: "Returns an upload whitelist entry." parameters: - name: "id" in: "path" required: true description: "The unique ID of the whitelist entry" schema: type: "integer" responses: 200: description: "The whitelist entry" content: application/json: schema: $ref: "#/components/schemas/UploadWhitelist" 403: description: "Access denied" 404: description: "Whitelist entry not found" /upload_karma_events.json: get: operationId: "getUploadKarmaEvents" x-access-level: "anonymous" tags: - "upload_karma_events" summary: "Get a list of upload karma events" description: "Returns the upload karma ledger, newest first. Rows are immutable once written." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of events to retrieve per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter events by event ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter events by creation date" schema: type: "string" - name: "search[user_id]" in: "query" required: false description: "Filter events by the affected user's ID. Accepts a comma-separated list." schema: type: "string" - name: "search[user_name]" in: "query" required: false description: "Filter events by the affected user's username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter events by the acting user's ID. Accepts a comma-separated list." schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter events by the acting user's username" schema: type: "string" - name: "search[post_id]" in: "query" required: false description: "Filter events by post ID" schema: type: "integer" - name: "search[reason]" in: "query" required: false description: "Filter events by reason" schema: $ref: "#/components/schemas/UploadKarmaEventReason" - name: "search[order]" in: "query" required: false description: "Order the results" schema: $ref: "#/components/schemas/GetUploadKarmaEventsSearchOrder" responses: 200: description: "A list of upload karma events" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/UploadKarmaEvent" 400: description: "Invalid request parameters" 500: description: "Server error" /forum_posts/new.json: get: operationId: "newForumPost" x-access-level: "member" tags: - "forum_posts" summary: "Prepare a new forum post" description: "Returns an unsaved forum post built from the supplied attributes." parameters: - name: "forum_post[body]" in: "query" required: false description: "The forum post body text" schema: type: "string" - name: "forum_post[topic_id]" in: "query" required: false description: "The ID of the forum topic to post in" schema: type: "integer" responses: 200: description: "An unsaved forum post" content: application/json: schema: $ref: "#/components/schemas/ForumPost" /forum_posts/{id}/edit.json: get: operationId: "editForumPost" x-access-level: "member" tags: - "forum_posts" summary: "Get a forum post for editing" parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 200: description: "A forum post" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 403: description: "Access denied" 404: description: "Forum post not found" /fposts.json: get: operationId: "searchForumPostsShorthand" x-access-level: "anonymous" tags: - "forum_posts" summary: "Search forum posts" description: "Shorthand alias for `GET /forum_posts.json`." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by forum post ID" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by update date" schema: type: "string" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[topic_id]" in: "query" required: false description: "Filter by forum topic ID" schema: type: "integer" - name: "search[topic_title_matches]" in: "query" required: false description: "Filter by topic title text" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Filter by post body text" schema: type: "string" - name: "search[topic_category_id]" in: "query" required: false description: "Filter by topic category ID" schema: type: "integer" - name: "search[is_hidden]" in: "query" required: false description: "Filter by hidden status" schema: type: "boolean" responses: 200: description: "A list of forum posts" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ForumPost" post: operationId: "createForumPostShorthand" x-access-level: "member" tags: - "forum_posts" summary: "Create a forum post" description: "Shorthand alias for `POST /forum_posts.json`." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateForumPostBody" responses: 201: description: "Forum post created" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 422: description: "Validation error" /fposts/new.json: get: operationId: "newForumPostShorthand" x-access-level: "member" tags: - "forum_posts" summary: "Prepare a new forum post" description: "Shorthand alias for `GET /forum_posts/new.json`." parameters: - name: "forum_post[body]" in: "query" required: false description: "The forum post body text" schema: type: "string" - name: "forum_post[topic_id]" in: "query" required: false description: "The ID of the forum topic to post in" schema: type: "integer" responses: 200: description: "An unsaved forum post" content: application/json: schema: $ref: "#/components/schemas/ForumPost" /fposts/{id}/edit.json: get: operationId: "editForumPostShorthand" x-access-level: "member" tags: - "forum_posts" summary: "Get a forum post for editing" description: "Shorthand alias for `GET /forum_posts/{id}/edit.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 200: description: "A forum post" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 403: description: "Access denied" 404: description: "Forum post not found" /fposts/{id}.json: get: operationId: "getForumPostShorthand" x-access-level: "anonymous" tags: - "forum_posts" summary: "Get a forum post by ID" description: "Shorthand alias for `GET /forum_posts/{id}.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 200: description: "A forum post" content: application/json: schema: $ref: "#/components/schemas/ForumPost" 403: description: "Access denied" 404: description: "Forum post not found" put: operationId: "updateForumPostShorthand" x-access-level: "member" tags: - "forum_posts" summary: "Update a forum post" description: "Shorthand alias for `PUT /forum_posts/{id}.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateForumPostBody" responses: 204: description: "Forum post updated" 403: description: "Access denied" 422: description: "Validation error" delete: operationId: "deleteForumPostShorthand" x-access-level: "admin" tags: - "forum_posts" summary: "Delete a forum post" description: "Shorthand alias for `DELETE /forum_posts/{id}.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum post" schema: type: "integer" responses: 200: description: "Forum post deleted" 403: description: "Access denied" 404: description: "Forum post not found" /forum_topics/new.json: get: operationId: "newForumTopic" x-access-level: "member" tags: - "forum_topics" summary: "Prepare a new forum topic" description: "Returns an unsaved forum topic built from the supplied attributes." parameters: - name: "forum_topic[title]" in: "query" required: false description: "The topic title" schema: type: "string" - name: "forum_topic[category_id]" in: "query" required: false description: "The forum category ID" schema: type: "integer" - name: "forum_topic[original_post_attributes][id]" in: "query" required: false description: "The ID of the original post" schema: type: "integer" - name: "forum_topic[original_post_attributes][body]" in: "query" required: false description: "The body text of the opening post" schema: type: "string" - name: "forum_topic[is_sticky]" in: "query" required: false description: "Whether the topic is sticky (moderator only)" schema: type: "boolean" - name: "forum_topic[is_locked]" in: "query" required: false description: "Whether the topic is locked (moderator only)" schema: type: "boolean" responses: 200: description: "An unsaved forum topic" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" /forum_topics/{id}/edit.json: get: operationId: "editForumTopic" x-access-level: "member" tags: - "forum_topics" summary: "Get a forum topic for editing" parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 200: description: "A forum topic" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 403: description: "Access denied" 404: description: "Forum topic not found" /ftopics.json: get: operationId: "searchForumTopicsShorthand" x-access-level: "anonymous" tags: - "forum_topics" summary: "Search forum topics" description: "Shorthand alias for `GET /forum_topics.json`." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by forum topic ID" schema: type: "integer" - name: "search[created_at]" in: "query" required: false description: "Filter by creation date" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by update date" schema: type: "string" - name: "search[title_matches]" in: "query" required: false description: "Filter by title text" schema: type: "string" - name: "search[title]" in: "query" required: false description: "Filter by exact title" schema: type: "string" - name: "search[category_id]" in: "query" required: false description: "Filter by forum category ID" schema: type: "integer" - name: "search[is_sticky]" in: "query" required: false description: "Filter by sticky status" schema: type: "boolean" - name: "search[is_locked]" in: "query" required: false description: "Filter by locked status" schema: type: "boolean" - name: "search[is_hidden]" in: "query" required: false description: "Filter by hidden status" schema: type: "boolean" - name: "search[order]" in: "query" required: false description: "Sort order (sticky)" schema: type: "string" responses: 200: description: "A list of forum topics" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ForumTopic" post: operationId: "createForumTopicShorthand" x-access-level: "member" tags: - "forum_topics" summary: "Create a forum topic" description: "Shorthand alias for `POST /forum_topics.json`." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateForumTopicBody" responses: 201: description: "Forum topic created" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 422: description: "Validation error" /ftopics/new.json: get: operationId: "newForumTopicShorthand" x-access-level: "member" tags: - "forum_topics" summary: "Prepare a new forum topic" description: "Shorthand alias for `GET /forum_topics/new.json`." parameters: - name: "forum_topic[title]" in: "query" required: false description: "The topic title" schema: type: "string" - name: "forum_topic[category_id]" in: "query" required: false description: "The forum category ID" schema: type: "integer" - name: "forum_topic[original_post_attributes][id]" in: "query" required: false description: "The ID of the original post" schema: type: "integer" - name: "forum_topic[original_post_attributes][body]" in: "query" required: false description: "The body text of the opening post" schema: type: "string" - name: "forum_topic[is_sticky]" in: "query" required: false description: "Whether the topic is sticky (moderator only)" schema: type: "boolean" - name: "forum_topic[is_locked]" in: "query" required: false description: "Whether the topic is locked (moderator only)" schema: type: "boolean" responses: 200: description: "An unsaved forum topic" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" /ftopics/{id}/edit.json: get: operationId: "editForumTopicShorthand" x-access-level: "member" tags: - "forum_topics" summary: "Get a forum topic for editing" description: "Shorthand alias for `GET /forum_topics/{id}/edit.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 200: description: "A forum topic" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 403: description: "Access denied" 404: description: "Forum topic not found" /ftopics/{id}.json: get: operationId: "getForumTopicShorthand" x-access-level: "anonymous" tags: - "forum_topics" summary: "Get a forum topic by ID" description: "Shorthand alias for `GET /forum_topics/{id}.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" - name: "page" in: "query" required: false description: "The page number for forum posts pagination" schema: type: "integer" responses: 200: description: "A forum topic" content: application/json: schema: $ref: "#/components/schemas/ForumTopic" 403: description: "Access denied" 404: description: "Forum topic not found" put: operationId: "updateForumTopicShorthand" x-access-level: "member" tags: - "forum_topics" summary: "Update a forum topic" description: "Shorthand alias for `PUT /forum_topics/{id}.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateForumTopicBody" responses: 204: description: "Forum topic updated" 403: description: "Access denied" 422: description: "Validation error" delete: operationId: "deleteForumTopicShorthand" x-access-level: "admin" tags: - "forum_topics" summary: "Delete a forum topic" description: "Shorthand alias for `DELETE /forum_topics/{id}.json`." parameters: - name: "id" in: "path" required: true description: "The ID of the forum topic" schema: type: "integer" responses: 200: description: "Forum topic deleted" 403: description: "Access denied" 404: description: "Forum topic not found" /comments/new.json: get: operationId: "newComment" x-access-level: "member" tags: - "comments" summary: "Prepare a new comment" description: "Returns an unsaved comment built from the supplied attributes." parameters: - name: "comment[body]" in: "query" required: false description: "The comment body text" schema: type: "string" - name: "comment[post_id]" in: "query" required: false description: "The ID of the post to comment on" schema: type: "integer" - name: "comment[do_not_bump_post]" in: "query" required: false description: "Whether to bump the post" schema: type: "boolean" - name: "comment[is_sticky]" in: "query" required: false description: "Whether the comment is sticky (staff only)" schema: type: "boolean" - name: "comment[is_hidden]" in: "query" required: false description: "Whether the comment is hidden (moderator only)" schema: type: "boolean" responses: 200: description: "An unsaved comment" content: application/json: schema: $ref: "#/components/schemas/Comment" /comments/{id}/edit.json: get: operationId: "editComment" x-access-level: "member" tags: - "comments" summary: "Get a comment for editing" parameters: - name: "id" in: "path" required: true description: "The ID of the comment" schema: type: "integer" responses: 200: description: "A comment" content: application/json: schema: $ref: "#/components/schemas/Comment" 403: description: "Access denied" 404: description: "Comment not found" /posts/{id}/comments.json: get: operationId: "getPostComments" x-access-level: "anonymous" tags: - "comments" summary: "Get the rendered comment section of a post" description: "Returns the comments of a post as pre-rendered HTML, together with the thumbnail attributes of every post referenced from them." parameters: - name: "id" in: "path" required: true description: "The ID of the post" schema: type: "integer" responses: 200: description: "The rendered comments of the post" content: application/json: schema: type: "object" properties: html: type: "string" posts: type: "object" 404: description: "Post not found" /blips/{id}/edit.json: get: operationId: "editBlip" x-access-level: "member" tags: - "blips" summary: "Get a blip for editing" parameters: - name: "id" in: "path" required: true description: "The ID of the blip" schema: type: "integer" responses: 200: description: "A blip" content: application/json: schema: $ref: "#/components/schemas/Blip" 403: description: "Access denied" 404: description: "Blip not found" 422: description: "The blip is more than five minutes old and the requester is not an admin" /wiki_pages/new.json: get: operationId: "newWikiPage" x-access-level: "member" tags: - "wiki_pages" summary: "Prepare a new wiki page" description: "Returns an unsaved wiki page built from the supplied attributes. Persisted fields such as the ID and timestamps are null." parameters: - name: "wiki_page[title]" in: "query" required: false description: "The title to prefill, normalized before it is returned" schema: type: "string" - name: "wiki_page[body]" in: "query" required: false description: "The body content to prefill" schema: type: "string" - name: "wiki_page[edit_reason]" in: "query" required: false description: "The edit reason to prefill" schema: type: "string" - name: "wiki_page[featured_posts_string]" in: "query" required: false description: "Space-separated post IDs to feature on the page" schema: type: "string" - name: "wiki_page[parent]" in: "query" required: false description: "The parent wiki page title (privileged+ only)" schema: type: "string" - name: "wiki_page[is_locked]" in: "query" required: false description: "Whether the page is locked (staff only)" schema: type: "boolean" - name: "wiki_page[is_deleted]" in: "query" required: false description: "Whether the page is deleted (staff only)" schema: type: "boolean" - name: "wiki_page[skip_secondary_validations]" in: "query" required: false description: "Whether to skip the rename post-count check (staff only)" schema: type: "boolean" responses: 200: description: "An unsaved wiki page" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 403: description: "Access denied, or a supplied attribute is not permitted at this user level" /wiki_pages/{id}/edit.json: get: operationId: "editWikiPage" x-access-level: "member" tags: - "wiki_pages" summary: "Get a wiki page for editing" description: "Returns the wiki page identified by ID or title, after checking that the current user may edit it." parameters: - name: "id" in: "path" required: true description: "The ID or title of the wiki page" schema: type: "string" responses: 200: description: "The wiki page to edit" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 403: description: "The wiki page is locked and the user is not staff" 404: description: "Wiki page not found" /wpages.json: get: operationId: "searchWpages" x-access-level: "anonymous" tags: - "wiki_pages" summary: "Search wiki pages" description: "Shorthand alias for /wiki_pages.json served by the same controller action." parameters: - name: "page" in: "query" required: false description: "The page number for pagination" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of results per page" schema: type: "integer" - name: "search[title]" in: "query" required: false description: "Filter by title (supports wildcards)" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Search by body text" schema: type: "string" - name: "search[other_names_match]" in: "query" required: false description: "Search by other names" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by creator user ID" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by creator username" schema: type: "string" - name: "search[hide_deleted]" in: "query" required: false description: "Hide deleted wiki pages" schema: type: "string" - name: "search[parent]" in: "query" required: false description: "Filter by parent wiki page" schema: type: "string" - name: "search[other_names_present]" in: "query" required: false description: "Filter by whether other names are present" schema: type: "string" - name: "search[is_locked]" in: "query" required: false description: "Filter by locked status" schema: type: "string" - name: "search[is_deleted]" in: "query" required: false description: "Filter by deleted status" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Sort order for results" schema: $ref: "#/components/schemas/SearchWikiPagesSearchOrder" responses: 200: description: "A list of wiki pages" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/WikiPage" post: operationId: "createWpage" x-access-level: "member" tags: - "wiki_pages" summary: "Create a wiki page" description: "Shorthand alias for /wiki_pages.json served by the same controller action." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWikiPageBody" responses: 201: description: "Wiki page created" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 403: description: "Access denied, or a supplied attribute is not permitted at this user level" 422: description: "Validation error" /wpages/new.json: get: operationId: "newWpage" x-access-level: "member" tags: - "wiki_pages" summary: "Prepare a new wiki page" description: "Shorthand alias for /wiki_pages/new.json served by the same controller action." parameters: - name: "wiki_page[title]" in: "query" required: false description: "The title to prefill, normalized before it is returned" schema: type: "string" - name: "wiki_page[body]" in: "query" required: false description: "The body content to prefill" schema: type: "string" - name: "wiki_page[edit_reason]" in: "query" required: false description: "The edit reason to prefill" schema: type: "string" - name: "wiki_page[featured_posts_string]" in: "query" required: false description: "Space-separated post IDs to feature on the page" schema: type: "string" - name: "wiki_page[parent]" in: "query" required: false description: "The parent wiki page title (privileged+ only)" schema: type: "string" - name: "wiki_page[is_locked]" in: "query" required: false description: "Whether the page is locked (staff only)" schema: type: "boolean" - name: "wiki_page[is_deleted]" in: "query" required: false description: "Whether the page is deleted (staff only)" schema: type: "boolean" - name: "wiki_page[skip_secondary_validations]" in: "query" required: false description: "Whether to skip the rename post-count check (staff only)" schema: type: "boolean" responses: 200: description: "An unsaved wiki page" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 403: description: "Access denied, or a supplied attribute is not permitted at this user level" /wpages/{id}/edit.json: get: operationId: "editWpage" x-access-level: "member" tags: - "wiki_pages" summary: "Get a wiki page for editing" description: "Shorthand alias for /wiki_pages/{id}/edit.json served by the same controller action." parameters: - name: "id" in: "path" required: true description: "The ID or title of the wiki page" schema: type: "string" responses: 200: description: "The wiki page to edit" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 403: description: "The wiki page is locked and the user is not staff" 404: description: "Wiki page not found" /wpages/{id}.json: get: operationId: "getWpage" x-access-level: "anonymous" tags: - "wiki_pages" summary: "Get a wiki page by ID or title" description: "Shorthand alias for /wiki_pages/{id}.json served by the same controller action." parameters: - name: "id" in: "path" required: true description: "The ID or title of the wiki page" schema: type: "string" responses: 200: description: "Wiki page details" content: application/json: schema: $ref: "#/components/schemas/WikiPage" 404: description: "Wiki page not found" put: operationId: "updateWpage" x-access-level: "member" tags: - "wiki_pages" summary: "Update a wiki page" description: "Shorthand alias for /wiki_pages/{id}.json served by the same controller action. Returns no content on success." parameters: - name: "id" in: "path" required: true description: "The ID of the wiki page to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateWikiPageBody" responses: 204: description: "Wiki page updated" 403: description: "The wiki page is locked and the user is not staff, or a supplied attribute is not permitted at this user level" 404: description: "Wiki page not found" 422: description: "Validation error" delete: operationId: "deleteWpage" x-access-level: "admin" tags: - "wiki_pages" summary: "Delete a wiki page" description: "Shorthand alias for /wiki_pages/{id}.json served by the same controller action. Returns no content on success." parameters: - name: "id" in: "path" required: true description: "The ID of the wiki page to delete" schema: type: "integer" responses: 204: description: "Wiki page deleted" 403: description: "Access denied" 404: description: "Wiki page not found" /artists/new.json: get: operationId: "newArtist" x-access-level: "member" tags: - "artists" summary: "Prepare a new artist" description: "Returns an unsaved artist built from the supplied attributes. Persisted fields such as the ID and timestamps are null." parameters: - name: "artist[name]" in: "query" required: false description: "The artist's tag name to prefill" schema: type: "string" - name: "artist[other_names]" in: "query" required: false description: "Space-separated alternative names to prefill" schema: type: "string" - name: "artist[other_names_string]" in: "query" required: false description: "Space-separated alternative names to prefill" schema: type: "string" - name: "artist[group_name]" in: "query" required: false description: "The artist group or circle name to prefill" schema: type: "string" - name: "artist[url_string]" in: "query" required: false description: "Newline-separated artist URLs to prefill" schema: type: "string" - name: "artist[notes]" in: "query" required: false description: "The artist wiki page body to prefill" schema: type: "string" - name: "artist[linked_user_id]" in: "query" required: false description: "The ID of the linked user account (staff only)" schema: type: "integer" - name: "artist[is_locked]" in: "query" required: false description: "Whether the artist page is locked (staff only)" schema: type: "boolean" responses: 200: description: "An unsaved artist" content: application/json: schema: $ref: "#/components/schemas/Artist" 403: description: "Access denied, or a supplied attribute is not permitted at this user level" /artists/show_or_new.json: get: operationId: "showOrNewArtist" x-access-level: "anonymous" tags: - "artists" summary: "Show an existing artist or prepare to create a new one" description: "Redirects to the artist with the given name if one exists, otherwise returns an unsaved artist carrying the normalized name." parameters: - name: "name" in: "query" required: false description: "The artist name to look up or create" schema: type: "string" responses: 200: description: "An unsaved artist carrying the normalized name" content: application/json: schema: $ref: "#/components/schemas/Artist" 302: description: "Redirect to the existing artist" /artists/{id}/edit.json: get: operationId: "editArtist" x-access-level: "member" tags: - "artists" summary: "Get an artist for editing" description: "Returns the artist identified by ID or name, after checking that the current user may edit it." parameters: - name: "id" in: "path" required: true description: "The artist ID or name" schema: type: "string" responses: 200: description: "The artist to edit" content: application/json: schema: $ref: "#/components/schemas/Artist" 403: description: "The artist is locked and the user is not staff" 404: description: "Artist not found" /artists/{id}/revert.json: put: operationId: "revertArtist" x-access-level: "member" tags: - "artists" summary: "Revert an artist to a previous version" description: "Reverts the artist to the given version. Returns no content on success." parameters: - name: "id" in: "path" required: true description: "The artist ID or name" schema: type: "string" - name: "version_id" in: "query" required: true description: "The ID of the artist version to revert to" schema: type: "integer" responses: 204: description: "Artist reverted" 403: description: "The artist is locked and the user is not staff" 404: description: "Artist or version not found" 422: description: "Validation error" /help/list.json: get: operationId: "listHelpPages" x-access-level: "anonymous" tags: - "help_pages" summary: "Get a list of help pages" description: "Returns every help page, sorted by display title. The result is cached for twelve hours and is not paginated." responses: 200: description: "A list of help pages" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/HelpPage" 500: description: "Server error" /help/new.json: get: operationId: "newHelpPage" x-access-level: "admin" tags: - "help_pages" summary: "Prepare a new help page" description: "Returns an unsaved help page. Every field is null, and the action accepts no attributes to prefill." responses: 200: description: "An unsaved help page" content: application/json: schema: $ref: "#/components/schemas/HelpPage" 403: description: "Access denied" /help/{id}/edit.json: get: operationId: "editHelpPage" x-access-level: "admin" tags: - "help_pages" summary: "Get a help page for editing" description: "Returns the help page with the given ID. Unlike the show action, this one accepts a numeric ID only." parameters: - name: "id" in: "path" required: true description: "The ID of the help page" schema: type: "integer" responses: 200: description: "The help page to edit" content: application/json: schema: $ref: "#/components/schemas/HelpPage" 403: description: "Access denied" 404: description: "Help page not found" /avoid_postings/new.json: get: operationId: "newAvoidPosting" x-access-level: "bd_staff" tags: - "avoid_postings" summary: "Prepare a new avoid posting entry" description: "Builds an unsaved avoid posting entry, but responds with an instance variable the action never assigns, so the body is always the JSON literal null." responses: 200: description: "Always the JSON literal null" 403: description: "Access denied" /takedowns/new.json: get: operationId: "newTakedown" x-access-level: "anonymous" tags: - "takedowns" summary: "Prepare a new takedown" description: "Returns an unsaved takedown. Every visible field is null, and the action accepts no attributes to prefill. Rejected while takedowns are disabled by site lockdown." responses: 200: description: "An unsaved takedown" content: application/json: schema: $ref: "#/components/schemas/Takedown" 403: description: "Takedowns are disabled" /tag_aliases/{id}/approve.json: post: operationId: "approveTagAlias" x-access-level: "admin" tags: - "tag_aliases" summary: "Approve a tag alias" description: "Queues a pending tag alias for processing and records the caller as its approver." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag alias" schema: type: "integer" responses: 201: description: "The approved tag alias" content: application/json: schema: $ref: "#/components/schemas/TagAlias" 403: description: "Access denied" 404: description: "Tag alias not found" 422: description: "Validation error" /tag_aliases/{id}/undo.json: post: operationId: "undoTagAlias" x-access-level: "admin" tags: - "tag_aliases" summary: "Undo a tag alias" description: "Queues a background job that reverses an applied tag alias. Requires unapplied undo data recorded when the alias was processed." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag alias" schema: type: "integer" responses: 201: description: "The tag alias whose undo was queued" content: application/json: schema: $ref: "#/components/schemas/TagAlias" 403: description: "Access denied, or the tag alias cannot be undone" 404: description: "Tag alias not found" /tag_implications/{id}/approve.json: post: operationId: "approveTagImplication" x-access-level: "admin" tags: - "tag_implications" summary: "Approve a tag implication" description: "Queues a pending tag implication for processing and records the caller as its approver." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag implication" schema: type: "integer" responses: 201: description: "The approved tag implication" content: application/json: schema: $ref: "#/components/schemas/TagImplication" 403: description: "Access denied" 404: description: "Tag implication not found" 422: description: "Validation error" /tag_implications/{id}/undo.json: post: operationId: "undoTagImplication" x-access-level: "admin" tags: - "tag_implications" summary: "Undo a tag implication" description: "Queues a background job that reverses an applied tag implication. Requires unapplied undo data recorded when the implication was processed." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag implication" schema: type: "integer" responses: 201: description: "The tag implication whose undo was queued" content: application/json: schema: $ref: "#/components/schemas/TagImplication" 403: description: "Access denied, or the tag implication cannot be undone" 404: description: "Tag implication not found" /tags/{id}/edit.json: get: operationId: "getEditTag" x-access-level: "member" tags: - "tags" summary: "Get a tag for editing" description: "Returns the tag to be edited. A non-admin caller is denied on a locked tag, on an admin-only category, and on a tag whose post count reaches the tag type change cutoff." parameters: - name: "id" in: "path" required: true description: "The unique ID of the tag to edit" schema: type: "integer" responses: 200: description: "The tag to edit" content: application/json: schema: $ref: "#/components/schemas/Tag" 403: description: "Access denied" 404: description: "Tag not found" /tags/{tag_id}/correction.json: get: operationId: "getTagCorrection" x-access-level: "anonymous" tags: - "tag_corrections" summary: "Get the post count correction data for a tag" description: "Compares a tag's cached post count against the count reported by the search index." parameters: - name: "tag_id" in: "path" required: true description: "The unique ID of the tag" schema: type: "integer" responses: 200: description: "The tag correction data" content: application/json: schema: $ref: "#/components/schemas/TagCorrection" 404: description: "Tag not found" post: operationId: "createTagCorrection" x-access-level: "staff" tags: - "tag_corrections" summary: "Fix a tag's post count" description: "Queues a job that recounts the tag's posts and refreshes its category cache. Nothing is queued unless commit is set to Fix. The response is always a redirect." parameters: - name: "tag_id" in: "path" required: true description: "The unique ID of the tag" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateTagCorrectionBody" responses: 302: description: "Redirects to the tag search or, when from_wiki is set, to the tag's wiki page" 403: description: "Access denied" 404: description: "Tag not found" /tags/{tag_id}/correction/new.json: get: operationId: "getNewTagCorrection" x-access-level: "staff" tags: - "tag_corrections" summary: "Get the post count correction data for a tag before fixing it" description: "Returns the same correction data as the correction endpoint, computed without a statement timeout." parameters: - name: "tag_id" in: "path" required: true description: "The unique ID of the tag" schema: type: "integer" responses: 200: description: "The tag correction data" content: application/json: schema: $ref: "#/components/schemas/TagCorrection" 403: description: "Access denied" 404: description: "Tag not found" /bulk_update_requests/new.json: get: operationId: "getNewBulkUpdateRequest" x-access-level: "member" tags: - "bulk_update_requests" summary: "Get a blank bulk update request" description: "Returns an unsaved bulk update request carrying the server-side defaults." responses: 200: description: "A blank bulk update request" content: application/json: schema: $ref: "#/components/schemas/BulkUpdateRequest" 403: description: "Access denied" /staff/wikis.json: get: operationId: "getStaffWikis" x-access-level: "staff" tags: - "staff" summary: "Get a list of staff wiki pages" description: "Returns a list of staff wiki pages matching the search criteria. Requires staff-level access." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of staff wiki pages to retrieve per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by staff wiki page ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the staff wiki page" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the staff wiki page" schema: type: "string" - name: "search[title]" in: "query" required: false description: "Filter by title, case-insensitively" schema: type: "string" - name: "search[body_matches]" in: "query" required: false description: "Filter by body text" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by the ID of the user who created the page" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by the username of the user who created the page" schema: type: "string" - name: "search[editor_id]" in: "query" required: false description: "Filter to pages that have a version updated by this user ID" schema: type: "integer" - name: "search[order]" in: "query" required: false description: "Order the results by a specific field" schema: $ref: "#/components/schemas/GetStaffWikisSearchOrder" responses: 200: description: "A list of staff wiki pages" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/StaffWiki" 403: description: "Access denied" post: operationId: "createStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Create a staff wiki page" description: "Creates a new staff wiki page. Requires staff-level access." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateStaffWikiBody" responses: 201: description: "The created staff wiki page" content: application/json: schema: $ref: "#/components/schemas/StaffWiki" 403: description: "Access denied" 422: description: "Validation error" /staff/wikis/new.json: get: operationId: "newStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Get a blank staff wiki page" description: "Returns an unsaved staff wiki page prefilled with the supplied attributes. Requires staff-level access." parameters: - name: "staff_wiki[title]" in: "query" required: false description: "The title to prefill" schema: type: "string" - name: "staff_wiki[body]" in: "query" required: false description: "The body to prefill" schema: type: "string" responses: 200: description: "An unsaved staff wiki page; persisted fields such as `id` and the timestamps are null" content: application/json: schema: $ref: "#/components/schemas/StaffWiki" 403: description: "Access denied" /staff/wikis/{id}.json: get: operationId: "getStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Get a staff wiki page by ID" description: "Returns detailed information about a specific staff wiki page. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page" schema: type: "integer" responses: 200: description: "Staff wiki page details" content: application/json: schema: $ref: "#/components/schemas/StaffWiki" 403: description: "Access denied" 404: description: "Staff wiki page not found" put: operationId: "updateStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Update a staff wiki page" description: "Updates an existing staff wiki page. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateStaffWikiBody" responses: 204: description: "Staff wiki page updated" 403: description: "Access denied" 404: description: "Staff wiki page not found" 422: description: "Validation error" delete: operationId: "deleteStaffWiki" x-access-level: "admin" tags: - "staff" summary: "Delete a staff wiki page" description: "Destroys a staff wiki page along with its versions and references. Requires admin-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page to delete" schema: type: "integer" responses: 204: description: "Staff wiki page deleted" 403: description: "Access denied" 404: description: "Staff wiki page not found" /staff/wikis/{id}/edit.json: get: operationId: "editStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Get a staff wiki page for editing" description: "Returns the staff wiki page that backs the edit form. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page" schema: type: "integer" responses: 200: description: "Staff wiki page details" content: application/json: schema: $ref: "#/components/schemas/StaffWiki" 403: description: "Access denied" 404: description: "Staff wiki page not found" /staff/wikis/{id}/revert.json: put: operationId: "revertStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Revert a staff wiki page to a previous version" description: "Restores the title and body of a staff wiki page from one of its versions. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page to revert" schema: type: "integer" - name: "version_id" in: "query" required: true description: "The ID of the version to revert to" schema: type: "integer" responses: 204: description: "Staff wiki page reverted" 403: description: "Access denied" 404: description: "Staff wiki page or version not found" 422: description: "Validation error" /staff/wikis/{id}/claim.json: post: operationId: "claimStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Claim a staff wiki page" description: "Sets the claimant of a staff wiki page to the current user. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page" schema: type: "integer" responses: 201: description: "The claimed staff wiki page" content: application/json: schema: $ref: "#/components/schemas/StaffWiki" 403: description: "Access denied" 404: description: "Staff wiki page not found" 422: description: "Validation error" /staff/wikis/{id}/unclaim.json: post: operationId: "unclaimStaffWiki" x-access-level: "staff" tags: - "staff" summary: "Unclaim a staff wiki page" description: "Clears the claimant of a staff wiki page. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page" schema: type: "integer" responses: 201: description: "The unclaimed staff wiki page" content: application/json: schema: $ref: "#/components/schemas/StaffWiki" 403: description: "Access denied" 404: description: "Staff wiki page not found" 422: description: "Validation error" /staff/files.json: get: operationId: "getStaffFiles" x-access-level: "staff" tags: - "staff" summary: "Get a list of staff files" description: "Returns a list of staff-uploaded files matching the search criteria. Requires staff-level access." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of staff files to retrieve per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by staff file ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the staff file" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the staff file" schema: type: "string" - name: "search[creator_id]" in: "query" required: false description: "Filter by the ID of the user who uploaded the file" schema: type: "integer" - name: "search[creator_name]" in: "query" required: false description: "Filter by the username of the user who uploaded the file" schema: type: "string" - name: "search[original_filename]" in: "query" required: false description: "Filter by the original filename, case-insensitively" schema: type: "string" - name: "search[file_ext]" in: "query" required: false description: "Filter by the file extension" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Order the results by a specific field" schema: $ref: "#/components/schemas/GetStaffFilesSearchOrder" responses: 200: description: "A list of staff files" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/StaffFile" 403: description: "Access denied" post: operationId: "createStaffFile" x-access-level: "staff" tags: - "staff" summary: "Upload a staff file" description: "Uploads a new staff file. Requires staff-level access." requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/CreateStaffFileBody" responses: 201: description: "The created staff file" content: application/json: schema: $ref: "#/components/schemas/StaffFile" 403: description: "Access denied" 422: description: "Validation error" /staff/files/new.json: get: operationId: "newStaffFile" x-access-level: "staff" tags: - "staff" summary: "Get a blank staff file" description: "Returns an unsaved, empty staff file record. Requires staff-level access." responses: 200: description: "An unsaved staff file; all fields are null" content: application/json: schema: $ref: "#/components/schemas/StaffFile" 403: description: "Access denied" /staff/files/{id}.json: get: operationId: "getStaffFile" x-access-level: "staff" tags: - "staff" summary: "Get a staff file by ID" description: "Returns detailed information about a specific staff file. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff file" schema: type: "integer" responses: 200: description: "Staff file details" content: application/json: schema: $ref: "#/components/schemas/StaffFile" 403: description: "Access denied" 404: description: "Staff file not found" put: operationId: "updateStaffFile" x-access-level: "staff" tags: - "staff" summary: "Update a staff file" description: "Updates the title and description of a staff file. The caller must be the uploader or an admin." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff file to update" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateStaffFileBody" responses: 204: description: "Staff file updated" 403: description: "Access denied when the caller is neither the uploader nor an admin" 404: description: "Staff file not found" 422: description: "Validation error" delete: operationId: "deleteStaffFile" x-access-level: "staff" tags: - "staff" summary: "Delete a staff file" description: "Destroys a staff file and removes the stored bytes. The caller must be the uploader or an admin." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff file to delete" schema: type: "integer" responses: 204: description: "Staff file deleted" 403: description: "Access denied when the caller is neither the uploader nor an admin" 404: description: "Staff file not found" /staff/files/{id}/edit.json: get: operationId: "editStaffFile" x-access-level: "staff" tags: - "staff" summary: "Get a staff file for editing" description: "Returns the staff file that backs the edit form. The caller must be the uploader or an admin." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff file" schema: type: "integer" responses: 200: description: "Staff file details" content: application/json: schema: $ref: "#/components/schemas/StaffFile" 403: description: "Access denied when the caller is neither the uploader nor an admin" 404: description: "Staff file not found" /staff/wiki_versions.json: get: operationId: "getStaffWikiVersions" x-access-level: "staff" tags: - "staff" summary: "Get a list of staff wiki page versions" description: "Returns a list of staff wiki page versions matching the search criteria. Requires staff-level access." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of versions to retrieve per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by version ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the version" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the version" schema: type: "string" - name: "search[staff_wiki_id]" in: "query" required: false description: "Filter by the ID of the staff wiki page the version belongs to" schema: type: "integer" - name: "search[updater_id]" in: "query" required: false description: "Filter by the ID of the user who made the edit" schema: type: "integer" - name: "search[updater_name]" in: "query" required: false description: "Filter by the username of the user who made the edit" schema: type: "string" - name: "search[title]" in: "query" required: false description: "Filter by the version title" schema: type: "string" - name: "search[body]" in: "query" required: false description: "Filter by the version body text" schema: type: "string" - name: "search[ip_addr]" in: "query" required: false description: "Filter by the updater's IP address or subnet. Only accepted from admins; ignored otherwise." schema: type: "string" responses: 200: description: "A list of staff wiki page versions" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/StaffWikiVersion" 403: description: "Access denied" /staff/wiki_versions/{id}.json: get: operationId: "getStaffWikiVersion" x-access-level: "staff" tags: - "staff" summary: "Get a staff wiki page version by ID" description: "Returns detailed information about a specific staff wiki page version. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the staff wiki page version" schema: type: "integer" responses: 200: description: "Staff wiki page version details" content: application/json: schema: $ref: "#/components/schemas/StaffWikiVersion" 403: description: "Access denied" 404: description: "Staff wiki page version not found" /staff/automod/dmails.json: get: operationId: "getAutomodDmails" x-access-level: "staff" tags: - "staff" summary: "Get a list of automod DMails" description: "Returns the DMails owned by the system user, which are the messages sent by automod. Requires staff-level access." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of DMails to retrieve per page" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by DMail ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the DMail" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the DMail" schema: type: "string" - name: "search[title_matches]" in: "query" required: false description: "Filter by the DMail subject line" schema: type: "string" - name: "search[message_matches]" in: "query" required: false description: "Filter by the DMail body text" schema: type: "string" - name: "search[to_id]" in: "query" required: false description: "Filter by the ID of the recipient" schema: type: "integer" - name: "search[to_name]" in: "query" required: false description: "Filter by the username of the recipient" schema: type: "string" - name: "search[from_id]" in: "query" required: false description: "Filter by the ID of the sender" schema: type: "integer" - name: "search[from_name]" in: "query" required: false description: "Filter by the username of the sender" schema: type: "string" - name: "search[is_read]" in: "query" required: false description: "Filter by whether the DMail has been read" schema: type: "boolean" - name: "search[is_deleted]" in: "query" required: false description: "Filter by whether the DMail has been deleted" schema: type: "boolean" - name: "search[read]" in: "query" required: false description: "When true, return only read DMails; when false, return only unread and undeleted DMails" schema: type: "boolean" responses: 200: description: "A list of automod DMails" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/Dmail" 403: description: "Access denied" /staff/automod/dmails/{id}.json: get: operationId: "getAutomodDmail" x-access-level: "staff" tags: - "staff" summary: "Get an automod DMail by ID" description: "Returns a single DMail owned by the system user. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the DMail" schema: type: "integer" responses: 200: description: "Automod DMail details" content: application/json: schema: $ref: "#/components/schemas/Dmail" 403: description: "Access denied" 404: description: "DMail not found or not owned by the system user" /staff/automod/dmails/{id}/mark_as_read.json: put: operationId: "markAutomodDmailAsRead" x-access-level: "staff" tags: - "staff" summary: "Mark an automod DMail as read" description: "Marks a system-owned DMail as read. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the DMail" schema: type: "integer" responses: 204: description: "DMail marked as read" 403: description: "Access denied" 404: description: "DMail not found or not owned by the system user" /staff/automod/dmails/{id}/mark_as_unread.json: put: operationId: "markAutomodDmailAsUnread" x-access-level: "staff" tags: - "staff" summary: "Mark an automod DMail as unread" description: "Marks a system-owned DMail as unread. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The unique ID of the DMail" schema: type: "integer" responses: 204: description: "DMail marked as unread" 403: description: "Access denied" 404: description: "DMail not found or not owned by the system user" /staff/exceptions.json: get: operationId: "getExceptionLogs" x-access-level: "staff" tags: - "staff" summary: "Get a list of exception logs" description: "Returns recorded server exceptions matching the search criteria. Always paginated at 100 entries per page. Requires staff-level access." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "search[id]" in: "query" required: false description: "Filter by exception log ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the exception log" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the exception log" schema: type: "string" - name: "search[user_name]" in: "query" required: false description: "Filter by the username of the user whose request raised the exception" schema: type: "string" - name: "search[code]" in: "query" required: false description: "Filter by the exception's public code" schema: type: "string" - name: "search[commit]" in: "query" required: false description: "Filter by the application version the exception was raised on" schema: type: "string" - name: "search[class_name]" in: "query" required: false description: "Filter by the exception class name" schema: type: "string" - name: "search[without_class_name]" in: "query" required: false description: "Exclude exceptions of this class name" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Order the results by a specific field" schema: $ref: "#/components/schemas/GetExceptionLogsSearchOrder" responses: 200: description: "A list of exception logs" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/ExceptionLog" 403: description: "Access denied" /staff/exceptions/{id}.json: get: operationId: "getExceptionLog" x-access-level: "staff" tags: - "staff" summary: "Get an exception log by ID or code" description: "Returns a single exception log. A purely numeric value is looked up by ID, anything else by the exception's code. Requires staff-level access." parameters: - name: "id" in: "path" required: true description: "The ID or the code of the exception log" schema: type: "string" responses: 200: description: "Exception log details" content: application/json: schema: $ref: "#/components/schemas/ExceptionLog" 403: description: "Access denied" 404: description: "Exception log not found" /staff/vote_trends.json: get: operationId: "getVoteTrends" x-access-level: "staff" tags: - "staff" summary: "Get post vote trends for a user" description: > Returns the tags, uploaders and ratings that a user's recent post votes cluster around, weighted by site-wide usage. Each entry is a two-element array of the trend subject and its score. Returns an empty array when `user` is missing or does not resolve to a user. Requires staff-level access. parameters: - name: "user" in: "query" required: false description: "The username of the user to analyse, or the user ID prefixed with `!`" schema: type: "string" - name: "limit" in: "query" required: false description: "The number of the user's most recent post votes to analyse" schema: type: "integer" - name: "threshold" in: "query" required: false description: "Minimum absolute weighted score for an entry to be returned" schema: type: "number" - name: "duration" in: "query" required: false description: "Only consider votes updated within this many days" schema: type: "number" - name: "disable_vote_normality" in: "query" required: false description: "Set to a non-zero integer to skip weighting votes by the post's score ratio" schema: type: "integer" responses: 200: description: "A list of `[subject, score]` pairs, ordered by ascending score" content: application/json: schema: type: "array" items: type: "array" description: "A two-element array: the trend subject followed by its weighted score" items: {} 403: description: "Access denied" /search_trends.json: get: operationId: "getSearchTrends" x-access-level: "anonymous" tags: - "search_trends" summary: "Get daily search trends" description: "Returns the recorded per-tag search counts for a single day, ordered by count descending then tag ascending." parameters: - name: "day" in: "query" required: false description: "The day to report on. Unparseable or missing values fall back to the current UTC date." schema: type: "string" format: "date" - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of trends to retrieve per page" schema: type: "integer" - name: "search[name_matches]" in: "query" required: false description: "Filter by tag name" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter by search trend ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the record" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the record" schema: type: "string" responses: 200: description: "A list of daily search trends" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/SearchTrend" 500: description: "Server error" /search_trends/rising.json: get: operationId: "getRisingSearchTrends" x-access-level: "anonymous" tags: - "search_trends" summary: "Get rising search trends" description: "Returns the tags whose search volume rose sharply over the last 24 hours compared with the preceding 24 hours. The list is cached for 15 minutes." responses: 200: description: "A list of rising tags" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/RisingSearchTrend" 500: description: "Server error" /search_trends/track.json: get: operationId: "trackSearchTrends" x-access-level: "anonymous" tags: - "search_trends" summary: "Get a 30 day history for tags" description: "Returns a complete 30 day daily series for each requested tag, with zero-count entries filled in for days that have no data." parameters: - name: "tag" in: "query" required: false description: "Comma-separated tag names. The value is downcased and stripped, duplicates are removed, and at most the first 10 tags are used." schema: type: "string" responses: 200: description: "A map of tag name to its daily series" content: application/json: schema: type: "object" description: "Keyed by tag name." additionalProperties: type: "array" items: $ref: "#/components/schemas/SearchTrendPoint" 500: description: "Server error" /search_trends/purge.json: delete: operationId: "purgeSearchTrends" x-access-level: "admin" tags: - "search_trends" summary: "Purge the recorded trends for a tag" description: "Deletes every daily and hourly search trend record for a single tag." parameters: - name: "tag" in: "query" required: false description: "The tag to purge. The value is downcased and stripped." schema: type: "string" responses: 200: description: "The number of records deleted" content: application/json: schema: $ref: "#/components/schemas/SearchTrendPurgeResult" 403: description: "Access denied" /search_trends/update_settings.json: post: operationId: "updateSearchTrendSettings" x-access-level: "admin" tags: - "search_trends" summary: "Update the search trend settings" description: "Updates the site-wide search trend settings and clears the rising tags cache. Only the keys present in the request are changed." requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/UpdateSearchTrendSettingsBody" responses: 200: description: "The settings were updated and the cache cleared" content: application/json: schema: $ref: "#/components/schemas/SearchTrendSettingsResult" 403: description: "Access denied" /search_trends/clear_cache.json: post: operationId: "clearSearchTrendCache" x-access-level: "admin" tags: - "search_trends" summary: "Clear the rising tags cache" description: "Deletes the cached rising tags list so it is recomputed on the next request." responses: 200: description: "The cache was cleared" content: application/json: schema: $ref: "#/components/schemas/SearchTrendSettingsResult" 403: description: "Access denied" /search_trend_blacklists.json: get: operationId: "getSearchTrendBlacklists" x-access-level: "admin" tags: - "search_trend_blacklists" summary: "Get a list of search trend blacklist entries" description: "Returns the tag patterns that are excluded from search trend recording." parameters: - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of entries to retrieve per page" schema: type: "integer" - name: "search[tag]" in: "query" required: false description: "Filter by tag pattern" schema: type: "string" - name: "search[reason]" in: "query" required: false description: "Filter by reason" schema: type: "string" - name: "search[id]" in: "query" required: false description: "Filter by blacklist entry ID" schema: type: "string" - name: "search[created_at]" in: "query" required: false description: "Filter by the creation date of the entry" schema: type: "string" - name: "search[updated_at]" in: "query" required: false description: "Filter by the last update date of the entry" schema: type: "string" - name: "search[order]" in: "query" required: false description: "Order the results" schema: $ref: "#/components/schemas/GetSearchTrendBlacklistsSearchOrder" responses: 200: description: "A list of search trend blacklist entries" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/SearchTrendBlacklist" 403: description: "Access denied" 500: description: "Server error" post: operationId: "createSearchTrendBlacklist" x-access-level: "admin" tags: - "search_trend_blacklists" summary: "Create a search trend blacklist entry" description: "Blacklists a tag pattern from search trend recording. The pattern supports the `*` and `?` globs, but a bare `*` is rejected." requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateSearchTrendBlacklistBody" responses: 201: description: "The created blacklist entry" content: application/json: schema: $ref: "#/components/schemas/SearchTrendBlacklist" 403: description: "Access denied" 422: description: "Validation error" /search_trend_blacklists/{id}.json: put: operationId: "updateSearchTrendBlacklist" x-access-level: "admin" tags: - "search_trend_blacklists" summary: "Update a search trend blacklist entry" description: "Updates the tag pattern or reason of an existing search trend blacklist entry." parameters: - name: "id" in: "path" required: true description: "The unique ID of the blacklist entry" schema: type: "integer" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateSearchTrendBlacklistBody" responses: 204: description: "The blacklist entry was updated" 403: description: "Access denied" 404: description: "Blacklist entry not found" 422: description: "Validation error" delete: operationId: "destroySearchTrendBlacklist" x-access-level: "admin" tags: - "search_trend_blacklists" summary: "Destroy a search trend blacklist entry" description: "Removes a search trend blacklist entry." parameters: - name: "id" in: "path" required: true description: "The unique ID of the blacklist entry" schema: type: "integer" responses: 204: description: "The blacklist entry was destroyed" 403: description: "Access denied" 404: description: "Blacklist entry not found" /search_trend_hourlies.json: get: operationId: "getSearchTrendHourlies" x-access-level: "admin" tags: - "search_trend_hourlies" summary: "Get hourly search trends" description: "Returns the per-tag search counts recorded for a single hour, ordered by count descending then tag ascending." parameters: - name: "hour" in: "query" required: false description: "The hour to report on, truncated to the start of the UTC hour. Unparseable or missing values fall back to the current hour." schema: type: "string" format: "date-time" - name: "page" in: "query" required: false description: "The page number to retrieve" schema: type: "integer" - name: "limit" in: "query" required: false description: "The number of records to retrieve per page" schema: type: "integer" - name: "search[name_matches]" in: "query" required: false description: "Filter by tag name" schema: type: "string" responses: 200: description: "A list of hourly search trend records" content: application/json: schema: type: "array" items: $ref: "#/components/schemas/SearchTrendHourly" 403: description: "Access denied" 500: description: "Server error" /stats.json: get: operationId: "getStats" x-access-level: "anonymous" tags: - "stats" summary: "Get site statistics" description: "Returns the cached site-wide statistics snapshot. An empty object is returned when the snapshot has not been generated yet." responses: 200: description: "The site statistics snapshot" content: application/json: schema: $ref: "#/components/schemas/Stats" 500: description: "Server error" components: securitySchemes: BasicAuth: type: "http" scheme: "basic" description: "HTTP Basic with the account username and an API key from `/api_keys.json`. The account password is not accepted." ApiKeyLogin: type: "apiKey" in: "query" name: "login" description: | Account username. Must be sent together with `api_key`. The server reads this from `params`, so it may also be sent in the request body, which `in: "query"` cannot express. ApiKeyQuery: type: "apiKey" in: "query" name: "api_key" description: | API key from `/api_keys.json`. Must be sent together with `login`. The server reads this from `params`, so it may also be sent in the request body, which `in: "query"` cannot express. parameters: PostV2Flag: name: "v2" in: "query" required: false description: "If `\"true\"`, the response uses the v2 Post format. Otherwise the legacy format is returned." schema: type: "string" enum: - "true" PostV2Mode: name: "mode" in: "query" required: false description: "Selects the v2 Post payload shape. Only effective when `v2=true`. Default `basic`." schema: type: "string" enum: - "basic" - "extended" - "thumbnail" - "thumbnails" schemas: LegacyPost: type: "object" required: - "id" - "created_at" - "updated_at" - "file" - "preview" - "sample" - "score" - "tags" - "locked_tags" - "change_seq" - "flags" - "rating" - "fav_count" - "sources" - "pools" - "relationships" - "uploader_id" - "description" - "comment_count" - "has_notes" properties: id: type: "integer" description: "The unique ID of the post" created_at: type: "string" format: "date-time" description: "The time when the post was created" updated_at: type: "string" format: "date-time" description: "The last time the post was updated" file: $ref: "#/components/schemas/File" preview: $ref: "#/components/schemas/Preview" sample: $ref: "#/components/schemas/Sample" score: $ref: "#/components/schemas/Score" tags: $ref: "#/components/schemas/Tags" locked_tags: type: "array" items: type: "string" description: "An array of tags that are locked" change_seq: type: "integer" description: "The sequence number of changes to the post" flags: $ref: "#/components/schemas/Flags" rating: $ref: "#/components/schemas/PostRating" fav_count: type: "integer" description: "The number of times the post has been favorited" sources: type: "array" items: type: "string" description: "An array of sources for the post" pools: type: "array" items: type: "integer" description: "An array of pool IDs associated with the post" relationships: $ref: "#/components/schemas/Relationships" approver_id: type: "integer" nullable: true description: "The ID of the user who approved the post, if applicable" uploader_id: type: "integer" description: "The ID of the user who uploaded the post" uploader_name: type: "string" description: "The username of the user who uploaded the post" description: type: "string" description: "The description of the post" comment_count: type: "integer" description: "The number of comments on the post" is_favorited: type: "boolean" description: "Whether the post is favorited by the current user" vote: type: "integer" description: "The requesting user's vote on the post, `1`, `-1`, or `0` when they have not voted or are not logged in" has_notes: type: "boolean" description: "Whether the post has any notes attached" duration: type: "number" nullable: true description: "The duration of the post, if applicable" File: type: "object" required: - "width" - "height" - "ext" - "size" - "md5" - "url" properties: width: type: "integer" description: "The width of the file in pixels" height: type: "integer" description: "The height of the file in pixels" ext: $ref: "#/components/schemas/FileExt" size: type: "integer" description: "The size of the file in bytes" md5: type: "string" description: "The MD5 hash of the file" url: type: "string" nullable: true description: "The URL of the file" Preview: type: "object" required: - "width" - "height" - "url" properties: width: type: "integer" description: "The width of the preview in pixels" height: type: "integer" description: "The height of the preview in pixels" url: type: "string" nullable: true description: "The URL of the preview image" alt: type: "string" nullable: true description: "The URL of the WebP preview image" Sample: type: "object" required: - "has" - "height" - "width" - "url" properties: has: type: "boolean" description: "Whether the sample exists" height: type: "integer" description: "The height of the sample image in pixels" width: type: "integer" description: "The width of the sample image in pixels" url: type: "string" nullable: true description: "The URL of the sample image" alt: type: "string" nullable: true description: "The URL of the WebP sample image" alternates: $ref: "#/components/schemas/SampleAlternates" Score: type: "object" required: - "up" - "down" - "total" properties: up: type: "integer" description: "The number of upvotes on the post" down: type: "integer" description: "The number of downvotes on the post" total: type: "integer" description: "The total score (upvotes minus downvotes)" Tags: type: "object" required: - "general" - "artist" - "contributor" - "copyright" - "character" - "species" - "invalid" - "meta" - "lore" properties: general: type: "array" items: type: "string" description: "An array of general tags" artist: type: "array" items: type: "string" description: "An array of artist tags" contributor: type: "array" items: type: "string" description: "An array of contributor tags" copyright: type: "array" items: type: "string" description: "An array of copyright tags" character: type: "array" items: type: "string" description: "An array of character tags" species: type: "array" items: type: "string" description: "An array of species tags" invalid: type: "array" items: type: "string" description: "An array of invalid tags" meta: type: "array" items: type: "string" description: "An array of meta tags" lore: type: "array" items: type: "string" description: "An array of lore tags" Flags: type: "object" required: - "pending" - "flagged" - "note_locked" - "status_locked" - "rating_locked" - "deleted" properties: pending: type: "boolean" description: "Whether the post is pending approval" flagged: type: "boolean" description: "Whether the post is flagged" note_locked: type: "boolean" description: "Whether notes on the post are locked" status_locked: type: "boolean" description: "Whether the status of the post is locked" rating_locked: type: "boolean" description: "Whether the rating of the post is locked" deleted: type: "boolean" description: "Whether the post is deleted" Relationships: type: "object" required: - "has_children" - "has_active_children" - "children" properties: parent_id: type: "integer" nullable: true description: "The ID of the parent post, if applicable" has_children: type: "boolean" description: "Whether the post has any child posts" has_active_children: type: "boolean" description: "Whether the post has any active child posts" children: type: "array" items: type: "integer" description: "An array of child post IDs" UserProfile: type: "object" description: "A detailed representation of a user." required: - "id" - "name" - "created_at" - "level" - "base_upload_limit" - "upload_karma" - "upload_karma_free" - "post_upload_count" - "post_update_count" - "note_update_count" - "is_banned" - "can_approve_posts" - "can_upload_free" - "level_string" properties: wiki_page_version_count: type: "integer" description: "Number of wiki page versions created by the user" artist_version_count: type: "integer" description: "Number of artist versions created by the user" pool_version_count: type: "integer" description: "Number of pool versions created by the user" forum_post_count: type: "integer" description: "Number of forum posts created by the user" comment_count: type: "integer" description: "Number of comments made by the user" flag_count: type: "integer" description: "Number of flags made by the user" favorite_count: type: "integer" description: "Number of favorites added by the user" positive_feedback_count: type: "integer" description: "Number of positive feedbacks received by the user" neutral_feedback_count: type: "integer" description: "Number of neutral feedbacks received by the user" negative_feedback_count: type: "integer" description: "Number of negative feedbacks received by the user" upload_slots: type: "integer" description: "The number of upload slots available to the user" profile_about: type: "string" description: "The user's \"About\" profile section" profile_artinfo: type: "string" description: "The user's art information profile section" id: type: "integer" description: "The unique ID of the user" created_at: type: "string" format: "date-time" description: "The timestamp when the user account was created" name: type: "string" description: "The username of the user" level: type: "integer" description: "The user's access level (numerical)" base_upload_limit: type: "integer" description: "The base upload limit for the user" upload_karma: type: "integer" description: "The user's upload karma" upload_karma_free: type: "boolean" description: "Whether the user is exempt from the upload karma system" post_upload_count: type: "integer" description: "Number of posts uploaded by the user" post_update_count: type: "integer" description: "Number of post updates made by the user" note_update_count: type: "integer" description: "Number of note updates made by the user" is_banned: type: "boolean" description: "Whether the user is banned" can_approve_posts: type: "boolean" description: "Whether the user can approve posts" can_upload_free: type: "boolean" description: "Whether the user can upload without restrictions" level_string: type: "string" description: "The user's access level (textual description)" avatar_id: type: "integer" description: "The ID of the user's avatar image" is_verified: type: "boolean" description: "Whether the user has verified their email" has_cropped_avatar: type: "boolean" description: "Whether the user has a server-side cropped avatar" User: type: "object" description: "A simplified representation of a user with core attributes." required: - "id" - "created_at" - "name" - "level" - "base_upload_limit" - "upload_karma" - "upload_karma_free" - "post_upload_count" - "post_update_count" - "note_update_count" - "is_banned" - "can_approve_posts" - "can_upload_free" - "level_string" properties: id: type: "integer" description: "The unique ID of the user" created_at: type: "string" format: "date-time" description: "The timestamp when the user account was created" name: type: "string" description: "The username of the user" level: type: "integer" description: "The user's access level (numerical)" base_upload_limit: type: "integer" description: "The base upload limit for the user" upload_karma: type: "integer" description: "The user's upload karma" upload_karma_free: type: "boolean" description: "Whether the user is exempt from the upload karma system" post_upload_count: type: "integer" description: "Number of posts uploaded by the user" post_update_count: type: "integer" description: "Number of post updates made by the user" note_update_count: type: "integer" description: "Number of note updates made by the user" is_banned: type: "boolean" description: "Whether the user is banned" can_approve_posts: type: "boolean" description: "Whether the user can approve posts" can_upload_free: type: "boolean" description: "Whether the user can upload without restrictions" level_string: type: "string" description: "The user's access level (textual description)" avatar_id: type: "integer" description: "The ID of the user's avatar image" is_verified: type: "boolean" description: "Whether the user has verified their email" has_cropped_avatar: type: "boolean" description: "Whether the user has a server-side cropped avatar" Ticket: type: "object" description: "A ticket object representing a user complaint or moderation issue." required: - "id" - "creator_id" - "reason" - "disp_id" - "qtype" - "status" - "created_at" - "updated_at" - "response" - "handler_id" properties: id: type: "integer" description: "The unique ID of the ticket" creator_id: type: "integer" description: "The ID of the user who created the ticket" reason: type: "string" description: "The reason for the ticket" disp_id: type: "integer" description: "The ID of the reported content associated with the ticket" qtype: $ref: "#/components/schemas/TicketQtype" status: $ref: "#/components/schemas/TicketStatus" created_at: type: "string" format: "date-time" description: "The time when the ticket was created" updated_at: type: "string" format: "date-time" description: "The last time the ticket was updated" response: type: "string" description: "The response to the ticket" handler_id: type: "integer" description: "The ID of the user handling the ticket" claimant_id: type: "integer" nullable: true description: "The ID of the claimant user" report_reason: type: "string" nullable: true description: "The post report reason for the ticket" accused_id: type: "integer" nullable: true description: "The ID of the accused user" Appeal: type: "object" description: | An appeal raised against a moderation action (currently only flag appeals). Field visibility depends on viewer permissions: users without view access do not receive `creator_id`, `accused_id`, `reason`, or `response`; non-staff users do not receive `claimant_id`. required: - "id" - "creator_id" - "disp_id" - "qtype" - "status" - "reason" - "response" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the appeal" creator_id: type: "integer" description: "The ID of the user who created the appeal" disp_id: type: "integer" description: "The ID of the appealed record (e.g. a PostFlag ID when `qtype=flag`)" qtype: $ref: "#/components/schemas/AppealQtype" status: $ref: "#/components/schemas/AppealStatus" reason: type: "string" description: "The reason given for the appeal" response: type: "string" description: "The handler's response to the appeal" claimant_id: type: "integer" nullable: true description: "The ID of the staff member currently claiming the appeal" handler_id: type: "integer" nullable: true description: "The ID of the staff member who last updated the appeal" accused_id: type: "integer" nullable: true description: "The ID of the user the appeal is filed against (e.g. the flag creator for flag appeals)" created_at: type: "string" format: "date-time" description: "The time the appeal was created" updated_at: type: "string" format: "date-time" description: "The last time the appeal was updated" UserFeedback: type: "object" description: "A user feedback object representing a piece of feedback left by a user." required: - "id" - "user_id" - "creator_id" - "created_at" - "body" - "category" - "updated_at" - "updater_id" - "is_deleted" properties: id: type: "integer" description: "The unique ID of the user feedback" user_id: type: "integer" description: "The ID of the user who received the feedback" creator_id: type: "integer" description: "The ID of the user who created the feedback" created_at: type: "string" format: "date-time" description: "The time when the feedback was created" body: type: "string" description: "The body of the feedback, containing the details" category: $ref: "#/components/schemas/UserFeedbackCategory" updated_at: type: "string" format: "date-time" description: "The last time the feedback was updated" updater_id: type: "integer" description: "The ID of the user who last updated the feedback" is_deleted: type: "boolean" description: "Whether the feedback is deleted" Approval: type: "object" description: "A post approval object representing a user's approval of a post." required: - "id" - "user_id" - "post_id" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the approval" user_id: type: "integer" description: "The ID of the user who approved the post" post_id: type: "integer" description: "The ID of the approved post" created_at: type: "string" format: "date-time" description: "The timestamp when the approval was created" updated_at: type: "string" format: "date-time" description: "The timestamp when the approval was last updated" Upload: type: "object" description: "An upload object representing a user's uploaded content." required: - "id" - "source" - "rating" - "uploader_id" - "status" - "created_at" - "updated_at" - "file_ext" - "file_size" - "image_width" - "image_height" - "uploader_name" properties: id: type: "integer" description: "The unique ID of the upload" source: type: "string" description: "The source URL of the upload, if provided" rating: $ref: "#/components/schemas/PostRating" uploader_id: type: "integer" description: "The ID of the user who uploaded the content" tag_string: type: "string" description: "The tags associated with the upload" status: type: "string" description: "The current status of the upload. May include details like \"duplicate: 12345\" or \"error: message\"" backtrace: type: "string" nullable: true description: "Any backtrace or error details if applicable" post_id: type: "integer" nullable: true description: "The ID of the post generated by this upload, if applicable" md5_confirmation: type: "string" nullable: true description: "The MD5 confirmation hash for the upload, if applicable" created_at: type: "string" format: "date-time" description: "The timestamp when the upload was created" updated_at: type: "string" format: "date-time" description: "The timestamp when the upload was last updated" parent_id: type: "integer" nullable: true description: "The ID of the parent post, if applicable" md5: type: "string" description: "The MD5 hash of the file" file_ext: type: "string" description: "The file extension (e.g., jpg, png, webm)" file_size: type: "integer" description: "The size of the file in bytes" image_width: type: "integer" description: "The width of the uploaded image in pixels" image_height: type: "integer" description: "The height of the uploaded image in pixels" description: type: "string" description: "A description of the uploaded content" uploader_name: type: "string" description: "The username of the uploader" PostFlag: type: "object" description: "A post flag object representing a user's flag or deletion of a post." required: - "id" - "created_at" - "post_id" - "reason" - "is_resolved" - "updated_at" - "is_deletion" - "type" - "needs_parent_id" - "needs_staff_reason" properties: id: type: "integer" description: "The unique ID of the post flag" created_at: type: "string" format: "date-time" description: "The timestamp when the post flag was created" post_id: type: "integer" description: "The ID of the post that the flag is related to" reason: type: "string" description: "The reason for the flag or deletion request" creator_id: type: "integer" description: "The ID of the user who created the flag or deletion request" is_resolved: type: "boolean" description: "Whether the flag has been resolved" updated_at: type: "string" format: "date-time" description: "The timestamp when the post flag was last updated" is_deletion: type: "boolean" description: "Whether the flag is a deletion request" type: $ref: "#/components/schemas/PostFlagType" reason_name: type: "string" nullable: true description: "The configured flag reason this flag was raised under" needs_parent_id: type: "boolean" description: "Whether the flag requires a parent post ID before it can be resolved" needs_staff_reason: type: "boolean" description: "Whether the flag requires a staff-supplied reason" note: type: "string" nullable: true description: "Additional explanation regarding the flag" PostVersion: type: "object" description: "A version of a post, representing changes made to the post." required: - "id" - "post_id" - "version" - "updated_at" - "is_hidden" properties: id: type: "integer" description: "The unique ID of the post version" post_id: type: "integer" description: "The ID of the associated post" tags: type: "string" description: "The tags associated with the post version" updater_id: type: "integer" description: "The ID of the user who updated the post" updated_at: type: "string" format: "date-time" description: "The timestamp when the post version was updated" rating: $ref: "#/components/schemas/PostRating" parent_id: type: "integer" nullable: true description: "The ID of the parent post, if applicable" source: type: "string" description: "The source URL associated with the post version" description: type: "string" description: "The description of the post version" reason: type: "string" nullable: true description: "The reason for the update, if applicable" locked_tags: type: "string" nullable: true description: "The locked tags associated with the post version" added_tags: type: "array" items: type: "string" description: "An array of tags added in this version" removed_tags: type: "array" items: type: "string" description: "An array of tags removed in this version" added_locked_tags: type: "array" items: type: "string" description: "An array of locked tags added in this version" removed_locked_tags: type: "array" items: type: "string" description: "An array of locked tags removed in this version" rating_changed: type: "boolean" description: "Whether the rating was changed in this version" parent_changed: type: "boolean" description: "Whether the parent ID was changed in this version" source_changed: type: "boolean" description: "Whether the source was changed in this version" description_changed: type: "boolean" description: "Whether the description was changed in this version" version: type: "integer" description: "The version number of the post" updater_name: type: "string" description: "The username of the user who updated the post version" is_hidden: type: "boolean" description: "Whether this version is hidden" PostReplacement: type: "object" description: "A post replacement object representing a file replacement request for a post." required: - "id" - "created_at" - "updated_at" - "post_id" - "creator_id" - "file_ext" - "file_size" - "image_height" - "image_width" - "md5" - "source" - "file_name" - "status" - "reason" properties: id: type: "integer" description: "The unique ID of the post replacement" created_at: type: "string" format: "date-time" description: "The timestamp when the replacement was created" updated_at: type: "string" format: "date-time" description: "The timestamp when the replacement was last updated" post_id: type: "integer" description: "The ID of the post associated with the replacement" creator_id: type: "integer" description: "The ID of the user who created the replacement" approver_id: type: "integer" nullable: true description: "The ID of the user who approved the replacement, if applicable" file_ext: type: "string" description: "The file extension of the replacement (e.g., jpg, png, webm)" file_size: type: "integer" description: "The size of the replacement file in bytes" image_height: type: "integer" description: "The height of the replacement image in pixels" image_width: type: "integer" description: "The width of the replacement image in pixels" md5: type: "string" description: "The MD5 hash of the replacement file" source: type: "string" description: "The source URLs for the replacement, separated by newlines" file_name: type: "string" description: "The name of the replacement file" status: $ref: "#/components/schemas/PostReplacementStatus" reason: type: "string" description: "The reason for the replacement request" sequence_number: type: "integer" nullable: true description: "The position of this replacement in the post's replacement history" ModAction: type: "object" description: "A moderation action representing administrative actions taken on the platform." required: - "id" - "creator_id" - "created_at" - "updated_at" - "action" - "values" properties: id: type: "integer" description: "The unique ID of the moderation action" creator_id: type: "integer" description: "The ID of the user who performed the moderation action" created_at: type: "string" format: "date-time" description: "The timestamp when the moderation action was created" updated_at: type: "string" format: "date-time" description: "The timestamp when the moderation action was last updated" action: $ref: "#/components/schemas/ModActionAction" values: $ref: "#/components/schemas/ModActionValues" BulkUpdateRequest: type: "object" required: - "id" - "user_id" - "script" - "status" - "created_at" - "updated_at" - "title" properties: id: type: "integer" description: "The unique ID of the bulk update request" user_id: type: "integer" description: "The ID of the user who created the request" forum_topic_id: type: "integer" description: "The ID of the forum topic associated with the request" script: type: "string" description: "The script content of the bulk update request" status: $ref: "#/components/schemas/BulkUpdateRequestStatus" created_at: type: "string" format: "date-time" description: "The timestamp when the request was created" updated_at: type: "string" format: "date-time" description: "The timestamp when the request was last updated" approver_id: type: "integer" nullable: true description: "The ID of the user who approved the request, if applicable" forum_post_id: type: "integer" description: "The ID of the forum post associated with the request" title: type: "string" description: "The title of the bulk update request" TagAlias: type: "object" required: - "id" - "antecedent_name" - "consequent_name" - "status" - "created_at" - "updated_at" - "creator_id" properties: id: type: "integer" description: "The unique ID of the tag alias" antecedent_name: type: "string" description: "The name of the antecedent tag" consequent_name: type: "string" description: "The name of the consequent tag" status: $ref: "#/components/schemas/TagAliasStatus" created_at: type: "string" format: "date-time" description: "The timestamp when the tag alias was created" updated_at: type: "string" format: "date-time" description: "The timestamp when the tag alias was last updated" reason: type: "string" description: "The reason for creating the tag alias" creator_id: type: "integer" description: "The ID of the user who created the tag alias" approver_id: type: "integer" nullable: true description: "The ID of the user who approved the tag alias, if applicable" forum_post_id: type: "integer" description: "The ID of the associated forum post" forum_topic_id: type: "integer" description: "The ID of the associated forum topic" post_count: type: "integer" description: "The number of posts associated with the tag alias" TagImplication: type: "object" required: - "id" - "antecedent_name" - "consequent_name" - "status" - "created_at" - "updated_at" - "creator_id" properties: id: type: "integer" description: "The unique ID of the tag implication" antecedent_name: type: "string" description: "The name of the antecedent tag" consequent_name: type: "string" description: "The name of the consequent tag" status: $ref: "#/components/schemas/TagImplicationStatus" created_at: type: "string" format: "date-time" description: "The timestamp when the tag implication was created" updated_at: type: "string" format: "date-time" description: "The timestamp when the tag implication was last updated" reason: type: "string" description: "The reason for creating the tag implication" creator_id: type: "integer" description: "The ID of the user who created the tag implication" approver_id: type: "integer" nullable: true description: "The ID of the user who approved the tag implication, if applicable" forum_post_id: type: "integer" description: "The ID of the associated forum post" forum_topic_id: type: "integer" description: "The ID of the associated forum topic" descendant_names: type: "array" items: type: "string" description: "A list of descendant tag names derived from this implication" PostEvent: type: "object" required: - "id" - "creator_id" - "post_id" - "action" - "created_at" properties: id: type: "integer" description: "The unique ID of the post event" creator_id: type: "integer" nullable: true description: "The ID of the user who performed the action, or null when the creator is not visible to the requester" post_id: type: "integer" description: "The ID of the post that was affected" action: $ref: "#/components/schemas/PostEventAction" created_at: type: "string" format: "date-time" description: "The timestamp when the event occurred" Artist: type: "object" required: - "id" - "name" - "creator_id" - "is_active" - "is_locked" - "other_names" - "group_name" - "linked_user_id" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the artist" name: type: "string" description: "The artist's tag name" creator_id: type: "integer" description: "The ID of the user who created the artist entry" is_active: type: "boolean" description: "Whether the artist is active" is_locked: type: "boolean" description: "Whether the artist page is locked for editing" other_names: type: "array" items: type: "string" description: "Alternative names for the artist" group_name: type: "string" description: "The name of the artist group or circle" linked_user_id: type: "integer" nullable: true description: "The ID of the linked user account" created_at: type: "string" format: "date-time" description: "The time when the artist was created" updated_at: type: "string" format: "date-time" description: "The last time the artist was updated" urls: type: "array" items: $ref: "#/components/schemas/ArtistUrl" description: "The artist's URLs" ArtistUrl: type: "object" properties: id: type: "integer" description: "The unique ID of the URL entry" artist_id: type: "integer" description: "The ID of the associated artist" url: type: "string" description: "The URL" normalized_url: type: "string" description: "The normalized form of the URL" is_active: type: "boolean" description: "Whether the URL is active" created_at: type: "string" format: "date-time" description: "The time when the URL was added" updated_at: type: "string" format: "date-time" description: "The last time the URL was updated" EditHistory: type: "object" required: - "id" - "versionable_id" - "versionable_type" - "version" - "body" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the edit history entry" versionable_id: type: "integer" description: "The ID of the edited item" versionable_type: $ref: "#/components/schemas/GetEditHistoryType" user_id: type: "integer" description: "The ID of the user who made the edit" body: type: "string" description: "The body content at this version" subject: type: "string" nullable: true description: "The subject at this version (for forum posts)" version: type: "integer" description: "The version number" ip_addr: type: "string" nullable: true description: "The IP address of the editor" created_at: type: "string" format: "date-time" description: "The time when this version was created" updated_at: type: "string" format: "date-time" description: "The last time this version was updated" Comment: type: "object" required: - "id" - "post_id" - "creator_id" - "body" - "score" - "created_at" - "updated_at" - "updater_id" - "do_not_bump_post" - "is_hidden" - "is_sticky" properties: id: type: "integer" description: "The unique ID of the comment" post_id: type: "integer" description: "The ID of the post this comment belongs to" creator_id: type: "integer" description: "The ID of the user who created the comment" body: type: "string" description: "The comment body text" score: type: "integer" description: "The comment score" created_at: type: "string" format: "date-time" description: "The time when the comment was created" updated_at: type: "string" format: "date-time" description: "The last time the comment was updated" updater_id: type: "integer" nullable: true description: "The ID of the user who last updated the comment" do_not_bump_post: type: "boolean" description: "Whether the comment should not bump the post" is_hidden: type: "boolean" description: "Whether the comment is hidden" is_sticky: type: "boolean" description: "Whether the comment is sticky" warning_type: type: "integer" nullable: true description: "The type of warning applied to the comment" warning_user_id: type: "integer" nullable: true description: "The ID of the user who applied the warning" creator_name: type: "string" description: "The username of the comment creator" updater_name: type: "string" nullable: true description: "The username of the last updater" vote: type: "integer" description: "The requesting user's vote on the comment. 0 when absent, locked or logged out" Blip: type: "object" required: - "id" - "creator_id" - "body" - "is_deleted" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the blip" creator_id: type: "integer" description: "The ID of the user who created the blip" body: type: "string" description: "The blip body text" response_to: type: "integer" nullable: true description: "The ID of the parent blip if this is a response" is_deleted: type: "boolean" description: "Whether the blip is deleted" created_at: type: "string" format: "date-time" description: "The time when the blip was created" updated_at: type: "string" format: "date-time" description: "The last time the blip was updated" warning_type: type: "integer" nullable: true description: "The type of warning applied to the blip" warning_user_id: type: "integer" nullable: true description: "The ID of the user who applied the warning" updater_id: type: "integer" nullable: true description: "The ID of the user who last updated the blip" creator_name: type: "string" description: "The username of the blip creator" ForumPost: type: "object" required: - "id" - "topic_id" - "creator_id" - "updater_id" - "body" - "is_hidden" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the forum post" topic_id: type: "integer" description: "The ID of the forum topic this post belongs to" creator_id: type: "integer" description: "The ID of the user who created the post" updater_id: type: "integer" description: "The ID of the user who last updated the post" body: type: "string" description: "The forum post body text" is_hidden: type: "boolean" description: "Whether the forum post is hidden" created_at: type: "string" format: "date-time" description: "The time when the forum post was created" updated_at: type: "string" format: "date-time" description: "The last time the forum post was updated" warning_type: type: "integer" nullable: true description: "The type of warning applied to the post" warning_user_id: type: "integer" nullable: true description: "The ID of the user who applied the warning" creator_name: type: "string" description: "The username of the post creator" updater_name: type: "string" description: "The username of the last updater" ForumTopic: type: "object" required: - "id" - "creator_id" - "updater_id" - "title" - "response_count" - "is_sticky" - "is_locked" - "is_hidden" - "created_at" - "updated_at" - "category_id" properties: id: type: "integer" description: "The unique ID of the forum topic" creator_id: type: "integer" description: "The ID of the user who created the topic" updater_id: type: "integer" description: "The ID of the user who last updated the topic" title: type: "string" description: "The topic title" response_count: type: "integer" description: "The number of responses in the topic" is_sticky: type: "boolean" description: "Whether the topic is sticky" is_locked: type: "boolean" description: "Whether the topic is locked" is_hidden: type: "boolean" description: "Whether the topic is hidden" created_at: type: "string" format: "date-time" description: "The time when the topic was created" updated_at: type: "string" format: "date-time" description: "The last time the topic was updated" category_id: type: "integer" description: "The forum category ID" creator_name: type: "string" description: "The username of the topic creator" updater_name: type: "string" description: "The username of the last updater" CommentVote: type: "object" required: - "id" - "comment_id" - "user_id" - "score" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the comment vote" comment_id: type: "integer" description: "The ID of the comment that was voted on" user_id: type: "integer" description: "The ID of the user who voted" score: $ref: "#/components/schemas/CommentVoteScore" created_at: type: "string" format: "date-time" description: "The time when the vote was cast" updated_at: type: "string" format: "date-time" description: "The last time the vote was updated" ForumPostVote: type: "object" required: - "id" - "forum_post_id" - "creator_id" - "score" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the forum post vote" forum_post_id: type: "integer" description: "The ID of the forum post that was voted on" creator_id: type: "integer" description: "The ID of the user who voted" score: $ref: "#/components/schemas/CommentVoteScore" created_at: type: "string" format: "date-time" description: "The time when the vote was cast" updated_at: type: "string" format: "date-time" description: "The last time the vote was updated" creator_name: type: "string" description: "The username of the voter" Tag: type: "object" required: - "id" - "name" - "post_count" - "category" - "is_locked" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the tag" name: type: "string" description: "The name of the tag" post_count: type: "integer" description: "The number of posts with this tag" category: type: "integer" description: "The category ID of the tag" related_tags: type: "string" nullable: true description: "Space-separated related tags with counts" related_tags_updated_at: type: "string" format: "date-time" nullable: true description: "When related tags were last updated" is_locked: type: "boolean" description: "Whether the tag category is locked" created_at: type: "string" format: "date-time" description: "When the tag was created" updated_at: type: "string" format: "date-time" description: "When the tag was last updated" TagTypeVersion: type: "object" required: - "id" - "tag_id" - "old_type" - "new_type" - "is_locked" - "creator_id" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the tag type version" tag_id: type: "integer" description: "The ID of the tag that was changed" old_type: type: "integer" description: "The previous category ID" new_type: type: "integer" description: "The new category ID" is_locked: type: "boolean" description: "Whether the tag was locked at time of change" creator_id: type: "integer" description: "The ID of the user who made the change" created_at: type: "string" format: "date-time" description: "When the change was made" updated_at: type: "string" format: "date-time" description: "When the record was last updated" WikiPage: type: "object" required: - "id" - "creator_id" - "title" - "body" - "is_locked" - "is_deleted" - "other_names" - "featured_posts" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the wiki page" creator_id: type: "integer" description: "The ID of the user who created the wiki page" creator_name: type: "string" description: "The username of the creator" title: type: "string" description: "The title of the wiki page" body: type: "string" description: "The body content of the wiki page" is_locked: type: "boolean" description: "Whether the wiki page is locked" is_deleted: type: "boolean" description: "Whether the wiki page is deleted" other_names: type: "array" items: type: "string" description: "Alternative names for the wiki page" featured_posts: type: "array" items: type: "integer" description: "The IDs of the posts featured on the wiki page" updater_id: type: "integer" nullable: true description: "The ID of the user who last updated the wiki page" parent: type: "string" nullable: true description: "The parent wiki page title for redirects" category_id: type: "integer" nullable: true description: "The tag category ID associated with the wiki page" created_at: type: "string" format: "date-time" description: "When the wiki page was created" updated_at: type: "string" format: "date-time" description: "When the wiki page was last updated" WikiPageVersion: type: "object" required: - "id" - "wiki_page_id" - "updater_id" - "title" - "body" - "is_locked" - "is_deleted" - "other_names" - "featured_posts" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the wiki page version" wiki_page_id: type: "integer" description: "The ID of the wiki page" updater_id: type: "integer" description: "The ID of the user who made this version" title: type: "string" description: "The title at this version" body: type: "string" description: "The body content at this version" is_locked: type: "boolean" description: "Whether the page was locked at this version" is_deleted: type: "boolean" description: "Whether the page was deleted at this version" other_names: type: "array" items: type: "string" description: "Alternative names at this version" featured_posts: type: "array" items: type: "integer" description: "The IDs of the posts featured on the page at this version" reason: type: "string" nullable: true description: "The edit reason for this version" parent: type: "string" nullable: true description: "The parent wiki page title at this version" created_at: type: "string" format: "date-time" description: "When this version was created" updated_at: type: "string" format: "date-time" description: "When this version was last updated" Note: type: "object" required: - "id" - "creator_id" - "post_id" - "x" - "y" - "width" - "height" - "is_active" - "body" - "version" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the note" creator_id: type: "integer" description: "The ID of the user who created the note" creator_name: type: "string" description: "The username of the creator" post_id: type: "integer" description: "The ID of the post the note is on" x: type: "integer" description: "X coordinate of the note" y: type: "integer" description: "Y coordinate of the note" width: type: "integer" description: "Width of the note" height: type: "integer" description: "Height of the note" is_active: type: "boolean" description: "Whether the note is active" body: type: "string" description: "The body text of the note" version: type: "integer" description: "The version number of the note" created_at: type: "string" format: "date-time" description: "When the note was created" updated_at: type: "string" format: "date-time" description: "When the note was last updated" NoteVersion: type: "object" required: - "id" - "note_id" - "post_id" - "updater_id" - "x" - "y" - "width" - "height" - "is_active" - "body" - "version" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the note version" note_id: type: "integer" description: "The ID of the note" post_id: type: "integer" description: "The ID of the post the note is on" updater_id: type: "integer" description: "The ID of the user who made this version" x: type: "integer" description: "X coordinate at this version" y: type: "integer" description: "Y coordinate at this version" width: type: "integer" description: "Width at this version" height: type: "integer" description: "Height at this version" is_active: type: "boolean" description: "Whether the note was active at this version" body: type: "string" description: "The body text at this version" version: type: "integer" description: "The version number" created_at: type: "string" format: "date-time" description: "When this version was created" updated_at: type: "string" format: "date-time" description: "When this version was last updated" Pool: type: "object" required: - "id" - "name" - "creator_id" - "is_active" - "post_ids" - "category" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the pool" name: type: "string" description: "The name of the pool" creator_id: type: "integer" description: "The ID of the pool creator" creator_name: type: "string" description: "The username of the pool creator" description: type: "string" description: "The pool description" is_active: type: "boolean" description: "Whether the pool is active" post_ids: type: "array" items: type: "integer" description: "Ordered array of post IDs in the pool" post_count: type: "integer" description: "The number of posts in the pool" category: $ref: "#/components/schemas/PoolCategory" created_at: type: "string" format: "date-time" description: "When the pool was created" updated_at: type: "string" format: "date-time" description: "When the pool was last updated" PoolVersion: type: "object" required: - "id" - "pool_id" - "post_ids" - "added_post_ids" - "removed_post_ids" - "version" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the pool version" pool_id: type: "integer" description: "The ID of the pool" post_ids: type: "array" items: type: "integer" description: "The full ordered list of post IDs at this version" added_post_ids: type: "array" items: type: "integer" description: "Post IDs added in this version" removed_post_ids: type: "array" items: type: "integer" description: "Post IDs removed in this version" updater_id: type: "integer" description: "The ID of the user who made this version" description: type: "string" nullable: true description: "The pool description at this version" description_changed: type: "boolean" description: "Whether the description was changed in this version" name: type: "string" nullable: true description: "The pool name at this version" name_changed: type: "boolean" description: "Whether the name was changed in this version" is_active: type: "boolean" description: "Whether the pool was active at this version" category: type: "string" nullable: true description: "The pool category at this version" version: type: "integer" description: "The version number" created_at: type: "string" format: "date-time" description: "When this version was created" updated_at: type: "string" format: "date-time" description: "When this version was last updated" PostSet: type: "object" required: - "id" - "name" - "shortname" - "is_public" - "creator_id" - "post_ids" - "post_count" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the post set" name: type: "string" description: "The name of the post set" shortname: type: "string" description: "The short name of the post set" description: type: "string" description: "The post set description" is_public: type: "boolean" description: "Whether the post set is publicly visible" transfer_on_delete: type: "boolean" description: "Whether to transfer favorites on delete" creator_id: type: "integer" description: "The ID of the set creator" post_ids: type: "array" items: type: "integer" description: "Ordered array of post IDs in the set" post_count: type: "integer" description: "The number of posts in the set" created_at: type: "string" format: "date-time" description: "When the post set was created" updated_at: type: "string" format: "date-time" description: "When the post set was last updated" PostVote: type: "object" description: "A vote on a post." required: - "id" - "post_id" - "user_id" - "score" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the vote" post_id: type: "integer" description: "The ID of the voted post" user_id: type: "integer" description: "The ID of the voting user" score: type: "integer" description: "The vote score (1, 0, or -1)" created_at: type: "string" format: "date-time" description: "When the vote was cast" updated_at: type: "string" format: "date-time" description: "When the vote was last updated" PostDisapproval: type: "object" description: "A disapproval of a pending post by an approver." required: - "id" - "post_id" - "user_id" - "reason" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the disapproval" post_id: type: "integer" description: "The ID of the disapproved post" user_id: type: "integer" description: "The ID of the disapproving user" reason: $ref: "#/components/schemas/PostDisapprovalReason" message: type: "string" nullable: true description: "Optional message explaining the disapproval" created_at: type: "string" format: "date-time" description: "When the disapproval was created" updated_at: type: "string" format: "date-time" description: "When the disapproval was last updated" Dmail: type: "object" description: "A direct message between users." required: - "id" - "owner_id" - "from_id" - "to_id" - "title" - "body" - "is_read" - "is_deleted" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the DMail" owner_id: type: "integer" description: "The ID of the user who owns this copy of the DMail" from_id: type: "integer" description: "The ID of the sender" to_id: type: "integer" description: "The ID of the recipient" title: type: "string" description: "The subject line of the DMail" body: type: "string" description: "The body text of the DMail" is_read: type: "boolean" description: "Whether the DMail has been read" is_deleted: type: "boolean" description: "Whether the DMail has been deleted" to_name: type: "string" description: "The recipient's username" from_name: type: "string" description: "The sender's username" created_at: type: "string" format: "date-time" description: "When the DMail was created" updated_at: type: "string" format: "date-time" description: "When the DMail was last updated" ApiKey: type: "object" description: "An API key for authenticating API requests." required: - "id" - "user_id" - "name" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the API key" user_id: type: "integer" description: "The ID of the user who owns the key" name: type: "string" description: "The name of the API key" key: type: "string" description: "The API key token (only shown on creation)" created_at: type: "string" format: "date-time" description: "When the API key was created" updated_at: type: "string" format: "date-time" description: "When the API key was last updated" last_used_at: type: "string" format: "date-time" nullable: true description: "When the API key was last used" last_ip_address: type: "string" nullable: true description: "The last IP address that used this key" expires_at: type: "string" format: "date-time" nullable: true description: "When the API key expires" Ban: type: "object" description: "A user ban record." required: - "id" - "user_id" - "banner_id" - "reason" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the ban" user_id: type: "integer" description: "The ID of the banned user" banner_id: type: "integer" description: "The ID of the staff member who issued the ban" reason: type: "string" description: "The reason for the ban" expires_at: type: "string" format: "date-time" nullable: true description: "When the ban expires (null for permanent bans)" created_at: type: "string" format: "date-time" description: "When the ban was created" updated_at: type: "string" format: "date-time" description: "When the ban was last updated" UserNameChangeRequest: type: "object" description: "A request to change a user's name." required: - "id" - "user_id" - "original_name" - "desired_name" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the name change request" status: type: "string" description: "The status of the request" user_id: type: "integer" description: "The ID of the user requesting the change" approver_id: type: "integer" nullable: true description: "The ID of the approving moderator" original_name: type: "string" description: "The user's original name" desired_name: type: "string" description: "The requested new name" change_reason: type: "string" nullable: true description: "The reason for the name change" rejection_reason: type: "string" nullable: true description: "The reason for rejecting the request" created_at: type: "string" format: "date-time" description: "When the request was created" updated_at: type: "string" format: "date-time" description: "When the request was last updated" StaffNote: type: "object" description: "A staff-only note on a user." required: - "id" - "user_id" - "creator_id" - "body" - "is_deleted" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the staff note" user_id: type: "integer" description: "The ID of the user the note is about" creator_id: type: "integer" description: "The ID of the staff member who created the note" updater_id: type: "integer" description: "The ID of the staff member who last updated the note" body: type: "string" description: "The body text of the staff note" is_deleted: type: "boolean" description: "Whether the staff note has been deleted" created_at: type: "string" format: "date-time" description: "When the staff note was created" updated_at: type: "string" format: "date-time" description: "When the staff note was last updated" AvoidPosting: type: "object" description: "An avoid posting (Do Not Post) entry for an artist." required: - "id" - "creator_id" - "updater_id" - "artist_id" - "is_active" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the avoid posting entry" creator_id: type: "integer" description: "The ID of the user who created the entry" updater_id: type: "integer" description: "The ID of the user who last updated the entry" artist_id: type: "integer" description: "The ID of the associated artist" details: type: "string" description: "Details about the avoid posting entry" staff_notes: type: "string" description: "Staff-only notes (hidden from non-staff users)" is_active: type: "boolean" description: "Whether the entry is active" created_at: type: "string" format: "date-time" description: "When the entry was created" updated_at: type: "string" format: "date-time" description: "When the entry was last updated" AvoidPostingVersion: type: "object" description: "A version history entry for an avoid posting record." required: - "id" - "updater_id" - "avoid_posting_id" - "is_active" - "updated_at" properties: id: type: "integer" description: "The unique ID of the version" updater_id: type: "integer" description: "The ID of the user who made this version" avoid_posting_id: type: "integer" description: "The ID of the associated avoid posting entry" details: type: "string" description: "Details at this version" staff_notes: type: "string" description: "Staff notes at this version (hidden from non-janitors)" is_active: type: "boolean" description: "Whether the entry was active at this version" updated_at: type: "string" format: "date-time" description: "When this version was created" Takedown: type: "object" description: "A takedown request. Most fields are hidden from non-staff users." required: - "id" - "status" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the takedown" status: $ref: "#/components/schemas/TakedownStatus" approver_id: type: "integer" nullable: true description: "The ID of the approving user" reason_hidden: type: "boolean" description: "Whether the reason is hidden" post_count: type: "integer" description: "The number of posts in the takedown" created_at: type: "string" format: "date-time" description: "When the takedown was created" updated_at: type: "string" format: "date-time" description: "When the takedown was last updated" IpBan: type: "object" description: "An IP address ban." required: - "id" - "creator_id" - "ip_addr" - "reason" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the IP ban" creator_id: type: "integer" description: "The ID of the staff member who created the ban" ip_addr: type: "string" description: "The banned IP address or CIDR range" reason: type: "string" description: "The reason for the ban" created_at: type: "string" format: "date-time" description: "When the ban was created" updated_at: type: "string" format: "date-time" description: "When the ban was last updated" ArtistVersion: type: "object" description: "A version history entry for an artist." required: - "id" - "artist_id" - "name" - "updater_id" - "is_active" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the version" artist_id: type: "integer" description: "The ID of the artist" name: type: "string" description: "The artist's name at this version" updater_id: type: "integer" description: "The ID of the user who made this version" is_active: type: "boolean" description: "Whether the artist was active at this version" group_name: type: "string" description: "The artist's group name at this version" other_names: type: "array" items: type: "string" description: "The artist's other names at this version" urls: type: "array" items: type: "string" description: "The artist's URLs at this version" notes_changed: type: "boolean" nullable: true description: "Whether the artist's notes were changed in this version" created_at: type: "string" format: "date-time" description: "When this version was created" updated_at: type: "string" format: "date-time" description: "When this version was last updated" UploadWhitelist: type: "object" description: "An upload whitelist entry controlling which domains are allowed for uploads." required: - "id" - "allowed" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the whitelist entry" domain: type: "string" description: "The domain pattern" path: type: "string" description: "The path pattern" note: type: "string" nullable: true description: "Note about the whitelist entry" reason: type: "string" nullable: true description: "The reason for the entry" allowed: type: "boolean" description: "Whether uploads from this domain are allowed" hidden: type: "boolean" description: "Whether the entry is hidden" created_at: type: "string" format: "date-time" description: "When the entry was created" updated_at: type: "string" format: "date-time" description: "When the entry was last updated" EmailBlacklist: type: "object" description: "A blacklisted email domain." required: - "id" - "domain" - "creator_id" - "reason" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the blacklist entry" domain: type: "string" description: "The blacklisted email domain" creator_id: type: "integer" description: "The ID of the staff member who created the entry" reason: type: "string" description: "The reason for blacklisting" created_at: type: "string" format: "date-time" description: "When the entry was created" updated_at: type: "string" format: "date-time" description: "When the entry was last updated" Mascot: type: "object" description: "A site mascot." required: - "id" - "creator_id" - "display_name" - "md5" - "file_ext" - "background_color" - "foreground_color" - "artist_url" - "artist_name" - "active" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the mascot" creator_id: type: "integer" description: "The ID of the user who created the mascot" display_name: type: "string" description: "The display name of the mascot" md5: type: "string" description: "The MD5 hash of the mascot image" file_ext: type: "string" description: "The file extension of the mascot image" background_color: type: "string" description: "Background color (hex)" foreground_color: type: "string" description: "Foreground color (hex)" artist_url: type: "string" description: "URL to the artist's page" artist_name: type: "string" description: "Name of the artist" active: type: "boolean" description: "Whether the mascot is active" available_on: type: "array" items: type: "string" description: "Sites the mascot is available on" is_layered: type: "boolean" description: "Whether the mascot is layered" url_path: type: "string" description: "URL path to the mascot image" created_at: type: "string" format: "date-time" description: "When the mascot was created" updated_at: type: "string" format: "date-time" description: "When the mascot was last updated" HelpPage: type: "object" description: "A help page linking to a wiki page." required: - "id" - "name" - "wiki_page" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the help page" name: type: "string" description: "The unique name identifier for the help page" wiki_page: type: "string" description: "The wiki page title this help page links to" related: type: "string" description: "Comma-separated related help page names" title: type: "string" description: "The display title for the help page" created_at: type: "string" format: "date-time" description: "When the help page was created" updated_at: type: "string" format: "date-time" description: "When the help page was last updated" NewsUpdate: type: "object" description: "A news update displayed on the site." required: - "id" - "message" - "creator_id" - "updater_id" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the news update" message: type: "string" description: "The news message content" creator_id: type: "integer" description: "The ID of the user who created the update" updater_id: type: "integer" description: "The ID of the user who last updated it" created_at: type: "string" format: "date-time" description: "When the news update was created" updated_at: type: "string" format: "date-time" description: "When the news update was last updated" RelatedTag: type: "object" description: "Related tags for a given query." properties: query: type: "string" description: "The query tag" category: type: "integer" nullable: true description: "The category ID filter" tags: type: "array" items: type: "array" items: type: "string" description: "A pair of [tag_name, tag_category_id]" description: "Array of related tag pairs" wiki_page_tags: type: "array" items: type: "string" description: "Tags found on the wiki page" PostFiles: type: "object" description: "File information for a v2 Post payload." required: - "meta" - "original" - "preview" - "sample" properties: meta: $ref: "#/components/schemas/PostFilesMeta" original: $ref: "#/components/schemas/PostFilesOriginal" preview: $ref: "#/components/schemas/PostFilesSample" sample: $ref: "#/components/schemas/PostFilesSample" video: $ref: "#/components/schemas/PostFilesVideo" PostStats: type: "object" required: - "score" - "fav_count" - "is_favorited" - "vote" - "comment_count" - "hotness" properties: score: $ref: "#/components/schemas/PostStatsScore" fav_count: type: "integer" is_favorited: type: "boolean" vote: type: "integer" description: "The requesting user's vote on the post, `1`, `-1`, or `0` when they have not voted or are not logged in" comment_count: type: "integer" hotness: type: "number" format: "float" description: "The post's hotness score" PostFlags: type: "object" required: - "pending" - "flagged" - "note_locked" - "status_locked" - "rating_locked" - "deleted" properties: pending: type: "boolean" flagged: type: "boolean" note_locked: type: "boolean" status_locked: type: "boolean" rating_locked: type: "boolean" deleted: type: "boolean" PostHas: type: "object" required: - "parent" - "children" - "active_children" - "notes" - "sample" properties: parent: type: "boolean" children: type: "boolean" active_children: type: "boolean" notes: type: "boolean" sample: type: "boolean" PostRelationships: type: "object" required: - "parent_id" - "children" properties: parent_id: type: "integer" nullable: true children: type: "array" items: type: "integer" PostBase: type: "object" description: "Common fields shared by the v2 basic and extended Post formats." required: - "id" - "created_at" - "updated_at" - "change_seq" - "files" - "uploader_id" - "uploader_name" - "approver_id" - "stats" - "flags" - "has" - "relationships" - "pools" - "rating" - "locked_tags" - "sources" - "description" properties: id: type: "integer" created_at: type: "string" format: "date-time" updated_at: type: "string" format: "date-time" change_seq: type: "integer" files: $ref: "#/components/schemas/PostFiles" uploader_id: type: "integer" uploader_name: type: "string" approver_id: type: "integer" nullable: true stats: $ref: "#/components/schemas/PostStats" flags: $ref: "#/components/schemas/PostFlags" has: $ref: "#/components/schemas/PostHas" relationships: $ref: "#/components/schemas/PostRelationships" pools: type: "array" items: type: "integer" rating: $ref: "#/components/schemas/PostRating" locked_tags: type: "array" items: type: "string" sources: type: "array" items: type: "string" description: type: "string" BasicPost: description: "Basic v2 Post payload (`v2=true`, `mode` unset or `basic`). Tags are a flat array of strings." allOf: - $ref: "#/components/schemas/PostBase" - type: "object" properties: tags: type: "array" items: type: "string" description: "All tags on the post." Post: description: "Extended v2 Post payload (`v2=true`, `mode=extended`). Tags are grouped by category name." allOf: - $ref: "#/components/schemas/PostBase" - type: "object" required: - "tags" properties: tags: $ref: "#/components/schemas/Tags" ThumbnailPost: type: "object" description: "Compact thumbnail v2 Post payload (`v2=true`, `mode=thumbnail` or `thumbnails`)." required: - "id" - "md5" - "created_at" - "file_ext" - "width" - "height" - "size" - "preview_url" - "preview_webp" - "sample_url" - "file_url" - "preview_width" - "preview_height" - "uploader_id" - "uploader" - "score" - "fav_count" - "is_favorited" - "vote" - "comment_count" - "flags" - "pools" - "rating" - "tags" properties: id: type: "integer" created_at: type: "string" format: "date-time" md5: type: "string" file_ext: type: "string" width: type: "integer" height: type: "integer" size: type: "integer" preview_url: type: "string" nullable: true preview_webp: type: "string" nullable: true sample_url: type: "string" nullable: true file_url: type: "string" nullable: true preview_width: type: "integer" preview_height: type: "integer" uploader_id: type: "integer" uploader: type: "string" score: type: "integer" fav_count: type: "integer" is_favorited: type: "boolean" vote: type: "integer" description: "The requesting user's vote on the post, `1`, `-1`, or `0` when they have not voted or are not logged in" comment_count: type: "integer" flags: type: "string" description: "Space-separated subset of \"pending\", \"flagged\", and \"deleted\"." pools: type: "string" description: "Space-separated list of pool IDs." rating: $ref: "#/components/schemas/PostRating" tags: type: "string" description: "Space-separated tag string." IqdbQuery: type: "object" description: "An IQDB similarity match result. The shape of `post` depends on the request's `v2` parameter." properties: post_id: type: "integer" description: "The ID of the matching post" score: type: "number" description: "The similarity score" post: oneOf: - $ref: "#/components/schemas/LegacyPost" - $ref: "#/components/schemas/BasicPost" description: "Basic v2 Post format when `v2=true`, legacy Post format otherwise." PostRating: type: "string" description: "The rating of the post (e.g., safe, questionable, explicit)" enum: - "s" - "q" - "e" FileExt: type: "string" description: "The file extension of the post's file" enum: - "jpg" - "png" - "gif" - "webm" - "mp4" - "swf" - "webp" SampleAlternates: type: "object" description: "Alternate versions of the sample for video posts" properties: has: type: "boolean" description: "Whether alternate versions exist" original: $ref: "#/components/schemas/SampleAlternatesOriginal" variants: $ref: "#/components/schemas/SampleAlternatesVariants" samples: $ref: "#/components/schemas/SampleAlternatesSamples" SampleAlternatesOriginal: type: "object" description: "The original video version" properties: codec: type: "string" nullable: true fps: type: "integer" size: type: "integer" width: type: "integer" height: type: "integer" url: type: "string" nullable: true SampleAlternatesVariants: type: "object" description: "Transcoded video variants keyed by name" additionalProperties: type: "object" properties: codec: type: "string" url: type: "string" nullable: true width: type: "integer" height: type: "integer" SampleAlternatesSamples: type: "object" description: "Sample versions keyed by name" additionalProperties: type: "object" properties: url: type: "string" nullable: true width: type: "integer" height: type: "integer" TicketQtype: type: "string" enum: - "user" - "comment" - "forum" - "blip" - "wiki" - "pool" - "set" - "post" - "dmail" - "replacement" description: "The type of ticket (e.g., comment, user, post)" AppealQtype: type: "string" enum: - "flag" description: "The kind of appeal" AppealStatus: type: "string" enum: - "pending" - "partial" - "approved" - "rejected" description: "The current status of the appeal" TicketStatus: type: "string" enum: - "pending" - "partial" - "approved" description: "The current status of the ticket" UserFeedbackCategory: type: "string" enum: - "negative" - "positive" - "neutral" description: "The category of the feedback (e.g., negative, positive, neutral)" PostFlagType: type: "string" description: "The type of the flag (e.g., flag or deletion)" enum: - "flag" - "deletion" PostReplacementStatus: type: "string" description: "The current status of the replacement" enum: - "original" - "pending" - "rejected" - "approved" - "promoted" ModActionAction: type: "string" description: "The type of moderation action performed" enum: - "admin_user_delete" - "artist_delete" - "artist_page_rename" - "artist_page_lock" - "artist_page_unlock" - "artist_user_linked" - "artist_user_unlinked" - "avoid_posting_create" - "avoid_posting_update" - "avoid_posting_delete" - "avoid_posting_undelete" - "avoid_posting_destroy" - "staff_note_create" - "staff_note_update" - "staff_note_delete" - "staff_note_undelete" - "blip_destroy" - "blip_delete" - "blip_undelete" - "blip_update" - "comment_delete" - "comment_hide" - "comment_unhide" - "comment_update" - "forum_category_create" - "forum_category_delete" - "forum_category_update" - "forum_post_delete" - "forum_post_hide" - "forum_post_unhide" - "forum_post_update" - "forum_topic_delete" - "forum_topic_hide" - "forum_topic_unhide" - "forum_topic_lock" - "forum_topic_unlock" - "forum_topic_stick" - "forum_topic_unstick" - "forum_topic_update" - "help_create" - "help_delete" - "help_update" - "ip_ban_create" - "ip_ban_delete" - "search_trend_blacklist_create" - "search_trend_blacklist_update" - "search_trend_blacklist_delete" - "search_trend_blacklist_purge" - "mascot_create" - "mascot_update" - "mascot_delete" - "staff_file_create" - "staff_file_update" - "staff_file_delete" - "pool_delete" - "flag_reason_create" - "flag_reason_update" - "flag_reason_delete" - "report_reason_create" - "report_reason_delete" - "report_reason_update" - "set_update" - "set_delete" - "set_change_visibility" - "tag_destroy" - "tag_alias_create" - "tag_alias_update" - "tag_alias_undo" - "tag_implication_create" - "tag_implication_update" - "tag_implication_undo" - "ticket_claim" - "ticket_unclaim" - "ticket_update" - "appeal_claim" - "appeal_unclaim" - "appeal_update" - "upload_whitelist_create" - "upload_whitelist_update" - "upload_whitelist_delete" - "user_avatar_clear" - "user_profile_clear" - "user_comments_hide" - "user_forum_posts_hide" - "user_blips_delete" - "user_blacklist_changed" - "user_text_change" - "user_custom_title_change" - "user_upload_limit_change" - "user_karma_change" - "user_karma_free_toggle" - "user_uploads_toggle" - "user_flags_change" - "user_level_change" - "user_name_change" - "totp_reset" - "password_reset" - "user_delete" - "user_ban" - "user_ban_update" - "user_unban" - "user_feedback_create" - "user_feedback_update" - "user_feedback_delete" - "user_feedback_undelete" - "user_feedback_destroy" - "user_flush_favorites" - "wiki_page_rename" - "wiki_page_delete" - "wiki_page_lock" - "wiki_page_unlock" - "mass_update" - "nuke_tag" - "takedown_delete" - "takedown_process" - "post_version_hide" - "post_version_unhide" ModActionValues: type: "object" description: "Additional details or parameters related to the moderation action" additionalProperties: type: "string" BulkUpdateRequestStatus: type: "string" description: "The current status of the request" enum: - "pending" - "approved" - "rejected" TagAliasStatus: type: "string" pattern: "^(active|deleted|pending|processing|queued|retired|error: .*)$" description: | The status of the tag alias. One of `active`, `deleted`, `pending`, `processing`, `queued`, `retired`, or `error: ` carrying the failure text when processing failed. TagImplicationStatus: type: "string" pattern: "^(active|deleted|pending|processing|queued|retired|error: .*)$" description: | The status of the tag implication. One of `active`, `deleted`, `pending`, `processing`, `queued`, `retired`, or `error: ` carrying the failure text when processing failed. PostEventAction: type: "string" description: "The action that was performed on the post" enum: - "deleted" - "undeleted" - "approved" - "unapproved" - "flag_created" - "flag_removed" - "favorites_moved" - "favorites_received" - "rating_locked" - "rating_unlocked" - "status_locked" - "status_unlocked" - "note_locked" - "note_unlocked" - "comment_locked" - "comment_unlocked" - "comment_disabled" - "comment_enabled" - "replacement_accepted" - "replacement_rejected" - "replacement_promoted" - "replacement_deleted" - "expunged" - "changed_bg_color" - "replacement_penalty_changed" - "owner_changed" - "replacement_moved" CommentVoteScore: type: "integer" description: "The vote score (1 for upvote, -1 for downvote, 0 for locked)" enum: - -1 - 0 - 1 PoolCategory: type: "string" enum: - "series" - "collection" description: "The pool category" PostDisapprovalReason: type: "string" description: "The reason for disapproval" enum: - "borderline_quality" - "borderline_relevancy" - "other" TakedownStatus: type: "string" description: "The status of the takedown" enum: - "pending" - "approved" - "denied" - "partial" PostFilesMeta: type: "object" required: - "md5" - "ext" - "size" - "duration" - "has_sample" properties: md5: type: "string" ext: type: "string" size: type: "integer" duration: type: "number" nullable: true has_sample: type: "boolean" PostFilesOriginal: type: "object" required: - "width" - "height" - "url" properties: width: type: "integer" height: type: "integer" url: type: "string" nullable: true PostFilesSample: type: "object" required: - "width" - "height" - "jpg" - "webp" properties: width: type: "integer" height: type: "integer" jpg: type: "string" nullable: true webp: type: "string" nullable: true PostFilesVideo: type: "object" description: "Only present for video posts." nullable: true PostStatsScore: type: "object" required: - "up" - "down" - "total" properties: up: type: "integer" down: type: "integer" total: type: "integer" GetUsersSearchOrder: type: "string" enum: - "date" - "name" - "post_upload_count" - "note_count" - "post_update_count" CreateUserBody: type: "object" required: - "user" properties: user: $ref: "#/components/schemas/CreateUserBodyUser" CreateUserBodyUser: type: "object" required: - "name" - "email" - "password" - "password_confirmation" properties: name: type: "string" description: "The desired username" email: type: "string" description: "The user's email address" password: type: "string" description: "The password for the account" password_confirmation: type: "string" description: "Password confirmation" UpdateUserBody: type: "object" required: - "user" properties: user: $ref: "#/components/schemas/UpdateUserBodyUser" UpdateUserBodyUser: type: "object" properties: comment_threshold: type: "integer" description: "Score threshold below which comments are hidden" default_image_size: type: "string" description: "Default image display size" favorite_tags: type: "string" description: "User's favorite tags" blacklisted_tags: type: "string" description: "Tags to blacklist" time_zone: type: "string" description: "User's time zone" per_page: type: "integer" description: "Number of items per page" custom_style: type: "string" description: "Custom CSS style" description_collapsed_initially: type: "boolean" description: "Whether post descriptions are collapsed by default" hide_comments: type: "boolean" description: "Whether to hide comments by default" receive_email_notifications: type: "boolean" description: "Whether to receive email notifications" enable_keyboard_navigation: type: "boolean" description: "Whether keyboard navigation is enabled" enable_privacy_mode: type: "boolean" description: "Whether privacy mode is enabled" disable_user_dmails: type: "boolean" description: "Whether to disable user DMails" blacklist_users: type: "boolean" description: "Whether to blacklist users" show_post_statistics: type: "boolean" description: "Whether to show post statistics" style_usernames: type: "boolean" description: "Whether to style usernames by level" show_hidden_comments: type: "boolean" description: "Whether to show hidden comments" enable_auto_complete: type: "boolean" description: "Whether auto-complete is enabled" enable_safe_mode: type: "boolean" description: "Whether safe mode is enabled" disable_responsive_mode: type: "boolean" description: "Whether responsive mode is disabled" profile_about: type: "string" description: "User's about me text" profile_artinfo: type: "string" description: "User's artist info text" avatar_id: type: "integer" description: "Post ID to use as avatar" password: type: "string" description: "New password" old_password: type: "string" description: "Current password (required when changing password)" password_confirmation: type: "string" description: "New password confirmation" CreateApiKeyBody: type: "object" required: - "api_key" properties: api_key: $ref: "#/components/schemas/CreateApiKeyBodyApiKey" CreateApiKeyBodyApiKey: type: "object" required: - "name" properties: name: type: "string" description: "A name for the API key" expires_at: type: "string" format: "date-time" description: "When the API key should expire" duration: type: "string" description: "Duration preset (e.g. \"30\", \"90\", \"never\", \"custom\")" GetBansSearchOrder: type: "string" enum: - "expires_at_desc" CreateStaffNoteBody: type: "object" required: - "staff_note" properties: staff_note: $ref: "#/components/schemas/CreateStaffNoteBodyStaffNote" CreateStaffNoteBodyStaffNote: type: "object" required: - "body" properties: body: type: "string" description: "The body text of the staff note" UpdateTicketBody: type: "object" properties: ticket[response]: type: "string" description: "The response to the ticket" ticket[status]: $ref: "#/components/schemas/TicketStatus" ticket[record_type]: type: "string" description: "The type of record to apply if the ticket content is warnable" ticket[send_update_dmail]: type: "boolean" description: "Whether to send a DMail notification about the update" force_claim: type: "boolean" description: "Force claiming the ticket even if already claimed by another user" GetAppealsSearchStatus: type: "string" enum: - "pending" - "pending_unclaimed" - "pending_claimed" - "partial" - "approved" - "rejected" - "handled" GetTicketsSearchStatus: type: "string" enum: - "pending" - "pending_unclaimed" - "pending_claimed" - "partial" - "approved" UpdateAppealBody: type: "object" properties: appeal[response]: type: "string" description: "The response to the appeal" appeal[status]: $ref: "#/components/schemas/AppealStatus" appeal[send_update_dmail]: type: "boolean" description: "Whether to send a DMail notification about the update" force_claim: type: "boolean" description: "Force claiming the appeal even if already claimed by another user" UpdateUserFeedbackBody: type: "object" properties: user_feedback: $ref: "#/components/schemas/UpdateUserFeedbackBodyUserFeedback" UpdateUserFeedbackBodyUserFeedback: type: "object" properties: body: type: "string" description: "New feedback body (DText supported)" category: $ref: "#/components/schemas/UserFeedbackCategory" send_update_dmail: type: "boolean" description: "Send DMail notification to the user about the update" GetUploadsSearchStatus: type: "string" description: | Matched against the upload status with SQL `LIKE`, where `*` is the wildcard. `completed`, `processing` and `pending` match exactly. The duplicate and error statuses carry a suffix (`duplicate: `, `error: `), so matching those needs a wildcard, as in `duplicate*`. CreatePostFlagBody: type: "object" required: - "post_flag" properties: post_flag: $ref: "#/components/schemas/CreatePostFlagBodyPostFlag" CreatePostFlagBodyPostFlag: type: "object" required: - "post_id" - "reason_name" properties: post_id: type: "integer" description: "The ID of the post to flag" reason_name: type: "string" description: "The reason for flagging" parent_id: type: "integer" description: "The parent post ID (for inferior duplicates)" note: type: "string" description: "Additional explanation for the flag" GetPostVersionsSearchRatingChanged: type: "string" enum: - "any" - "s" - "q" - "e" GetPostVersionsSearchUploads: type: "string" enum: - "only" - "included" - "excluded" GetUserFeedbacksSearchDeleted: type: "string" enum: - "included" - "excluded" - "only" GetPostReplacementsSearchStatus: type: "string" enum: - "original" - "pending" - "rejected" - "approved" - "promoted" CreatePostReplacementBody: type: "object" required: - "post_id" properties: post_id: type: "integer" description: "The ID of the post to replace" post_replacement[replacement_url]: type: "string" description: "URL of the replacement file" post_replacement[replacement_file]: type: "string" format: "binary" description: "The replacement file to upload" post_replacement[reason]: type: "string" description: "Reason for the replacement" post_replacement[source]: type: "string" description: "Source URL for the replacement" post_replacement[as_pending]: type: "boolean" description: "Whether to upload as pending" GetModActionsSearchAction: type: "string" enum: - "admin_user_delete" - "artist_delete" - "artist_page_rename" - "artist_page_lock" - "artist_page_unlock" - "artist_user_linked" - "artist_user_unlinked" - "avoid_posting_create" - "avoid_posting_update" - "avoid_posting_delete" - "avoid_posting_undelete" - "avoid_posting_destroy" - "staff_note_create" - "staff_note_update" - "staff_note_delete" - "staff_note_undelete" - "blip_destroy" - "blip_delete" - "blip_undelete" - "blip_update" - "comment_delete" - "comment_hide" - "comment_unhide" - "comment_update" - "forum_category_create" - "forum_category_delete" - "forum_category_update" - "forum_post_delete" - "forum_post_hide" - "forum_post_unhide" - "forum_post_update" - "forum_topic_delete" - "forum_topic_hide" - "forum_topic_unhide" - "forum_topic_lock" - "forum_topic_unlock" - "forum_topic_stick" - "forum_topic_unstick" - "forum_topic_update" - "help_create" - "help_delete" - "help_update" - "ip_ban_create" - "ip_ban_delete" - "search_trend_blacklist_create" - "search_trend_blacklist_update" - "search_trend_blacklist_delete" - "search_trend_blacklist_purge" - "mascot_create" - "mascot_update" - "mascot_delete" - "staff_file_create" - "staff_file_update" - "staff_file_delete" - "pool_delete" - "flag_reason_create" - "flag_reason_update" - "flag_reason_delete" - "report_reason_create" - "report_reason_delete" - "report_reason_update" - "set_update" - "set_delete" - "set_change_visibility" - "tag_destroy" - "tag_alias_create" - "tag_alias_update" - "tag_alias_undo" - "tag_implication_create" - "tag_implication_update" - "tag_implication_undo" - "ticket_claim" - "ticket_unclaim" - "ticket_update" - "appeal_claim" - "appeal_unclaim" - "appeal_update" - "upload_whitelist_create" - "upload_whitelist_update" - "upload_whitelist_delete" - "user_avatar_clear" - "user_profile_clear" - "user_comments_hide" - "user_forum_posts_hide" - "user_blips_delete" - "user_blacklist_changed" - "user_text_change" - "user_custom_title_change" - "user_upload_limit_change" - "user_karma_change" - "user_karma_free_toggle" - "user_uploads_toggle" - "user_flags_change" - "user_level_change" - "user_name_change" - "totp_reset" - "password_reset" - "user_delete" - "user_ban" - "user_ban_update" - "user_unban" - "user_feedback_create" - "user_feedback_update" - "user_feedback_delete" - "user_feedback_undelete" - "user_feedback_destroy" - "user_flush_favorites" - "wiki_page_rename" - "wiki_page_delete" - "wiki_page_lock" - "wiki_page_unlock" - "mass_update" - "nuke_tag" - "takedown_delete" - "takedown_process" - "post_version_hide" - "post_version_unhide" GetBulkUpdateRequestsSearchOrder: type: "string" enum: - "status_desc" - "updated_at_desc" - "id_desc" - "id_asc" CreateBulkUpdateRequestBody: type: "object" required: - "bulk_update_request[script]" properties: bulk_update_request[title]: type: "string" description: "The title of the request" bulk_update_request[script]: type: "string" description: "The BUR script content" bulk_update_request[reason]: type: "string" description: "The reason for the request" bulk_update_request[forum_topic_id]: type: "integer" description: "The forum topic ID to link to" bulk_update_request[skip_forum]: type: "boolean" description: "Skip forum post creation (admin only)" UpdateBulkUpdateRequestBody: type: "object" properties: bulk_update_request[script]: type: "string" description: "The BUR script content" bulk_update_request[forum_topic_id]: type: "integer" description: "The forum topic ID to link to (admin only)" bulk_update_request[forum_post_id]: type: "integer" description: "The forum post ID to link to (admin only)" GetTagAliasesSearchStatus: type: "string" enum: - "Approved" - "Active" - "Pending" - "Deleted" - "Retired" - "Processing" - "Queued" GetTagAliasesSearchOrder: type: "string" enum: - "id_desc" - "id_asc" - "status" - "created_at" - "updated_at" - "name" - "tag_count" GetTagImplicationsSearchOrder: type: "string" enum: - "id_desc" - "id_asc" - "status" - "created_at" - "updated_at" - "name" - "tag_count" GetTagImplicationsSearchStatus: type: "string" enum: - "Approved" - "Active" - "Pending" - "Deleted" - "Retired" - "Processing" - "Queued" GetArtistsSearchOrder: type: "string" enum: - "name" - "updated_at" - "post_count" - "created_at" GetEditHistoriesSearchOrder: type: "string" enum: - "updated_at" - "updated_at_desc" - "id" - "id_desc" GetEditHistoryType: type: "string" enum: - "Comment" - "ForumPost" - "Blip" SearchCommentsGroupBy: type: "string" enum: - "post" CreateCommentBody: type: "object" required: - "comment" properties: comment: $ref: "#/components/schemas/CreateCommentBodyComment" CreateCommentBodyComment: type: "object" required: - "body" - "post_id" properties: body: type: "string" description: "The comment body text" post_id: type: "integer" description: "The ID of the post to comment on" do_not_bump_post: type: "boolean" description: "Whether to bump the post" is_sticky: type: "boolean" description: "Whether the comment is sticky (janitor only)" is_hidden: type: "boolean" description: "Whether the comment is hidden (moderator only)" UpdateCommentBody: type: "object" required: - "comment" properties: comment: $ref: "#/components/schemas/UpdateCommentBodyComment" UpdateCommentBodyComment: type: "object" properties: body: type: "string" description: "The comment body text" is_sticky: type: "boolean" description: "Whether the comment is sticky (janitor only)" is_hidden: type: "boolean" description: "Whether the comment is hidden (moderator only)" CreateCommentVoteBody: type: "object" required: - "score" properties: score: $ref: "#/components/schemas/CreatePostVoteBodyScore" no_unvote: type: "boolean" description: "If true, do not unvote when voting again with the same score" CreateBlipBody: type: "object" required: - "blip" properties: blip: $ref: "#/components/schemas/CreateBlipBodyBlip" CreateBlipBodyBlip: type: "object" required: - "body" properties: body: type: "string" description: "The blip body text" response_to: type: "integer" description: "The ID of the blip to respond to" UpdateBlipBody: type: "object" required: - "blip" properties: blip: $ref: "#/components/schemas/UpdateBlipBodyBlip" UpdateBlipBodyBlip: type: "object" properties: body: type: "string" description: "The blip body text" WarningBlipRecordType: type: "string" enum: - "warning" - "record" - "ban" - "unmark" CreateForumTopicBody: type: "object" required: - "forum_topic" properties: forum_topic: $ref: "#/components/schemas/CreateForumTopicBodyForumTopic" CreateForumTopicBodyForumTopic: type: "object" required: - "title" - "category_id" - "original_post_attributes" properties: title: type: "string" description: "The topic title" category_id: type: "integer" description: "The forum category ID" original_post_attributes: $ref: "#/components/schemas/CreateStaffNoteBodyStaffNote" is_sticky: type: "boolean" description: "Whether the topic is sticky (moderator only)" is_locked: type: "boolean" description: "Whether the topic is locked (moderator only)" UpdateForumTopicBody: type: "object" required: - "forum_topic" properties: forum_topic: $ref: "#/components/schemas/UpdateForumTopicBodyForumTopic" UpdateForumTopicBodyForumTopic: type: "object" properties: title: type: "string" description: "The topic title" category_id: type: "integer" description: "The forum category ID" original_post_attributes: $ref: "#/components/schemas/UpdateForumTopicBodyForumTopicOriginalPostAttributes" is_sticky: type: "boolean" description: "Whether the topic is sticky (moderator only)" is_locked: type: "boolean" description: "Whether the topic is locked (moderator only)" UpdateForumTopicBodyForumTopicOriginalPostAttributes: type: "object" properties: id: type: "integer" description: "The ID of the original post" body: type: "string" description: "The body text of the opening post" CreateForumPostBody: type: "object" required: - "forum_post" properties: forum_post: $ref: "#/components/schemas/CreateForumPostBodyForumPost" CreateForumPostBodyForumPost: type: "object" required: - "body" - "topic_id" properties: body: type: "string" description: "The forum post body text" topic_id: type: "integer" description: "The ID of the forum topic to post in" UpdateForumPostBody: type: "object" required: - "forum_post" properties: forum_post: $ref: "#/components/schemas/UpdateBlipBodyBlip" CreateForumPostVoteBody: type: "object" required: - "forum_post_vote" properties: forum_post_vote: $ref: "#/components/schemas/CreateForumPostVoteBodyForumPostVote" CreateForumPostVoteBodyForumPostVote: type: "object" required: - "score" properties: score: $ref: "#/components/schemas/CommentVoteScore" SearchTagsSearchOrder: type: "string" enum: - "name" - "date" - "similarity" - "id_asc" - "id_desc" UpdateTagBody: type: "object" required: - "tag" properties: tag: $ref: "#/components/schemas/UpdateTagBodyTag" UpdateTagBodyTag: type: "object" properties: category: type: "integer" description: "The category ID for the tag" is_locked: type: "boolean" description: "Whether the tag is locked (admin only)" PreviewTagsBody: type: "object" properties: tags: type: "string" description: "The tags string to preview" SearchWikiPagesSearchOrder: type: "string" enum: - "title" - "post_count" CreateWikiPageBody: type: "object" required: - "wiki_page" properties: wiki_page: $ref: "#/components/schemas/CreateWikiPageBodyWikiPage" CreateWikiPageBodyWikiPage: type: "object" required: - "title" - "body" properties: title: type: "string" description: "The title of the wiki page" body: type: "string" description: "The body content of the wiki page" edit_reason: type: "string" description: "The reason for the edit" featured_posts_string: type: "string" description: "Space-separated IDs of the posts to feature on the page" parent: type: "string" description: "The parent wiki page title (privileged+ only)" is_locked: type: "boolean" description: "Whether the page is locked (staff only)" is_deleted: type: "boolean" description: "Whether the page is deleted (staff only)" skip_secondary_validations: type: "boolean" description: "Whether to skip the rename post-count check (staff only)" UpdateWikiPageBody: type: "object" required: - "wiki_page" properties: wiki_page: $ref: "#/components/schemas/UpdateWikiPageBodyWikiPage" UpdateWikiPageBodyWikiPage: type: "object" properties: body: type: "string" description: "The body content of the wiki page" edit_reason: type: "string" description: "The reason for the edit" featured_posts_string: type: "string" description: "Space-separated IDs of the posts to feature on the page" parent: type: "string" description: "The parent wiki page title (privileged+ only)" title: type: "string" description: "The title of the wiki page (staff only)" is_locked: type: "boolean" description: "Whether the page is locked (staff only)" is_deleted: type: "boolean" description: "Whether the page is deleted (staff only)" skip_secondary_validations: type: "boolean" description: "Whether to skip the rename post-count check (staff only)" CreateNoteBody: type: "object" required: - "note" properties: note: $ref: "#/components/schemas/CreateNoteBodyNote" CreateNoteBodyNote: type: "object" required: - "post_id" - "x" - "y" - "width" - "height" - "body" properties: post_id: type: "integer" description: "The ID of the post to attach the note to" x: type: "integer" description: "X coordinate of the note" y: type: "integer" description: "Y coordinate of the note" width: type: "integer" description: "Width of the note" height: type: "integer" description: "Height of the note" body: type: "string" description: "The body text of the note" html_id: type: "string" description: "HTML element ID for the note" UpdateNoteBody: type: "object" required: - "note" properties: note: $ref: "#/components/schemas/UpdateNoteBodyNote" UpdateNoteBodyNote: type: "object" properties: x: type: "integer" description: "X coordinate of the note" y: type: "integer" description: "Y coordinate of the note" width: type: "integer" description: "Width of the note" height: type: "integer" description: "Height of the note" body: type: "string" description: "The body text of the note" CreatePoolBody: type: "object" required: - "pool" properties: pool: $ref: "#/components/schemas/CreatePoolBodyPool" CreatePoolBodyPool: type: "object" required: - "name" properties: name: type: "string" description: type: "string" category: $ref: "#/components/schemas/PoolCategory" is_active: type: "boolean" post_ids: type: "array" items: type: "integer" UpdatePoolBody: type: "object" required: - "pool" properties: pool: $ref: "#/components/schemas/UpdatePoolBodyPool" UpdatePoolBodyPool: type: "object" properties: name: type: "string" description: type: "string" category: $ref: "#/components/schemas/PoolCategory" is_active: type: "boolean" post_ids: type: "array" items: type: "integer" AddPoolElementBody: type: "object" required: - "post_id" properties: pool_id: type: "integer" description: "The ID of the pool" pool_name: type: "string" description: "The name of the pool (alternative to pool_id)" post_id: type: "integer" description: "The ID of the post to add" SearchPostSetsSearchOrder: type: "string" enum: - "name" - "shortname" - "post_count" - "created_at" - "updated_at" CreatePostSetBody: type: "object" required: - "post_set" properties: post_set: $ref: "#/components/schemas/CreatePostSetBodyPostSet" CreatePostSetBodyPostSet: type: "object" required: - "name" - "shortname" properties: name: type: "string" shortname: type: "string" description: type: "string" is_public: type: "boolean" transfer_on_delete: type: "boolean" UpdatePostSetBody: type: "object" required: - "post_set" properties: post_set: $ref: "#/components/schemas/UpdatePostSetBodyPostSet" UpdatePostSetBodyPostSet: type: "object" properties: name: type: "string" shortname: type: "string" description: type: "string" is_public: type: "boolean" transfer_on_delete: type: "boolean" AddPostSetPostsBody: type: "object" required: - "post_ids" properties: post_ids: type: "array" items: type: "integer" description: "The IDs of posts to add" AddFavoriteBody: type: "object" required: - "post_id" properties: post_id: type: "integer" description: "The ID of the post to favorite" LockPostVotesBody: type: "object" required: - "ids" properties: ids: type: "string" description: "Comma-separated list of post vote IDs to lock" CreatePostVoteBody: type: "object" required: - "score" properties: score: $ref: "#/components/schemas/CreatePostVoteBodyScore" no_unvote: type: "boolean" description: "If true, do not remove an existing identical vote" CreatePostVoteBodyScore: type: "integer" description: "The vote score (1 for upvote, -1 for downvote)" enum: - 1 - -1 ResolvePostFlagApproval: type: "string" enum: - "approve" CreatePostDisapprovalBody: type: "object" required: - "post_disapproval" properties: post_disapproval: $ref: "#/components/schemas/CreatePostDisapprovalBodyPostDisapproval" CreatePostDisapprovalBodyPostDisapproval: type: "object" required: - "post_id" - "reason" properties: post_id: type: "integer" description: "The ID of the post to disapprove" reason: $ref: "#/components/schemas/PostDisapprovalReason" message: type: "string" description: "Optional message explaining the disapproval" StaffDeletePostBody: type: "object" required: - "reason" - "commit" properties: reason: type: "string" description: "The reason for deleting the post" commit: $ref: "#/components/schemas/StaffDeletePostBodyCommit" from_flag: type: "string" description: "Set if the deletion originates from a flag" copy_sources: type: "boolean" description: "Copy sources to the parent post" copy_tags: type: "boolean" description: "Copy tags to the parent post" move_favorites: type: "boolean" description: "Move favorites and post sets to the parent post" StaffDeletePostBodyCommit: type: "string" description: "Must be \"Delete\" to confirm deletion" enum: - "Delete" StaffExpungePostBody: type: "object" properties: reason: type: "string" description: "The reason for expunging the post" StaffMoveFavoritesBody: type: "object" required: - "commit" properties: commit: $ref: "#/components/schemas/StaffMoveFavoritesBodyCommit" StaffMoveFavoritesBodyCommit: type: "string" description: "Must be \"Submit\" to confirm the transfer" enum: - "Submit" GetAvoidPostingsSearchOrder: type: "string" enum: - "artist_name" - "artist_name_asc" - "artist_name_desc" - "created_at" - "updated_at" CreateAvoidPostingBody: type: "object" properties: avoid_posting[details]: type: "string" description: "Details about the avoid posting entry" avoid_posting[staff_notes]: type: "string" description: "Staff-only notes" avoid_posting[is_active]: type: "boolean" description: "Whether the entry is active" avoid_posting[artist_attributes][name]: type: "string" description: "The artist's name" avoid_posting[artist_attributes][other_names_string]: type: "string" description: "Other names for the artist (space-separated)" avoid_posting[artist_attributes][group_name]: type: "string" description: "The artist's group name" avoid_posting[artist_attributes][linked_user_id]: type: "integer" description: "The ID of the linked user" UpdateAvoidPostingBody: type: "object" properties: avoid_posting[details]: type: "string" description: "Details about the avoid posting entry" avoid_posting[staff_notes]: type: "string" description: "Staff-only notes" avoid_posting[is_active]: type: "boolean" description: "Whether the entry is active" GetTakedownsSearchOrder: type: "string" enum: - "status" - "post_count" UpdateTakedownBody: type: "object" properties: takedown[notes]: type: "string" description: "Staff notes for the takedown" takedown[reason_hidden]: type: "boolean" description: "Whether to hide the reason" takedown_posts: $ref: "#/components/schemas/UpdateTakedownBodyTakedownPosts" process_takedown: type: "boolean" description: "Whether to process the takedown" delete_reason: type: "string" description: "Reason for deleting posts" UpdateTakedownBodyTakedownPosts: type: "object" description: "Map of post IDs to keep/delete status" AddTakedownPostsByIdsBody: type: "object" properties: post_ids: type: "string" description: "Space-separated post IDs or URLs to add" AddTakedownPostsByTagsBody: type: "object" properties: post_tags: type: "string" description: "Tag query to find posts to add" CreateIpBanBody: type: "object" required: - "ip_ban[ip_addr]" - "ip_ban[reason]" properties: ip_ban[ip_addr]: type: "string" description: "The IP address or CIDR range to ban" ip_ban[reason]: type: "string" description: "The reason for the ban" GetArtistVersionsSearchOrder: type: "string" enum: - "name" GetUploadWhitelistsSearchOrder: type: "string" enum: - "domain" - "path" - "updated_at" - "created_at" CreateUploadWhitelistBody: type: "object" properties: upload_whitelist[allowed]: type: "boolean" description: "Whether uploads from this domain are allowed" upload_whitelist[domain]: type: "string" description: "The domain pattern" upload_whitelist[path]: type: "string" description: "The path pattern" upload_whitelist[reason]: type: "string" description: "The reason for the whitelist entry" upload_whitelist[note]: type: "string" description: "Note about the whitelist entry" upload_whitelist[hidden]: type: "boolean" description: "Whether the entry is hidden" GetPopularPostsScale: type: "string" enum: - "day" - "week" - "month" GetIqdbQueryV2: type: "string" enum: - "true" PostIqdbQueryBody: type: "object" properties: search[file]: type: "string" format: "binary" description: "An image file to find similar images for" search[url]: type: "string" description: "Find images similar to the image at this URL" search[post_id]: type: "integer" description: "Find images similar to this post" search[hash]: type: "string" description: "Find images similar to this perceptual hash" search[score_cutoff]: type: "number" description: "Minimum similarity score threshold" PostRelatedTagBulkBody: type: "object" properties: query: type: "string" description: "The tag query for bulk related tag lookup" category_id: type: "integer" description: "Filter by tag category ID" CreateDtextPreviewBody: type: "object" properties: body: type: "string" description: "The DText markup to render" allow_color: type: "boolean" description: "Whether to allow color tags" CreateMascotBody: type: "object" required: - "mascot[mascot_file]" - "mascot[display_name]" - "mascot[artist_url]" - "mascot[artist_name]" properties: mascot[mascot_file]: type: "string" format: "binary" description: "The mascot image file" mascot[display_name]: type: "string" description: "Display name for the mascot" mascot[background_color]: type: "string" description: "Background color (hex)" mascot[foreground_color]: type: "string" description: "Foreground color (hex)" mascot[is_layered]: type: "boolean" description: "Whether the mascot is layered" mascot[artist_url]: type: "string" description: "URL to the artist's page" mascot[artist_name]: type: "string" description: "Name of the artist" mascot[available_on_string]: type: "string" description: "Comma-separated list of sites the mascot is available on" mascot[active]: type: "boolean" description: "Whether the mascot is active" UpdateMascotBody: type: "object" properties: mascot[mascot_file]: type: "string" format: "binary" description: "The mascot image file" mascot[display_name]: type: "string" description: "Display name for the mascot" mascot[background_color]: type: "string" description: "Background color (hex)" mascot[foreground_color]: type: "string" description: "Foreground color (hex)" mascot[is_layered]: type: "boolean" description: "Whether the mascot is layered" mascot[artist_url]: type: "string" description: "URL to the artist's page" mascot[artist_name]: type: "string" description: "Name of the artist" mascot[available_on_string]: type: "string" description: "Comma-separated list of sites the mascot is available on" mascot[active]: type: "boolean" description: "Whether the mascot is active" CreateHelpPageBody: type: "object" required: - "help_page[name]" - "help_page[wiki_page]" properties: help_page[name]: type: "string" description: "The unique name identifier for the help page" help_page[wiki_page]: type: "string" description: "The wiki page title to link to" help_page[related]: type: "string" description: "Comma-separated related help page names" help_page[title]: type: "string" description: "The display title for the help page" UpdateHelpPageBody: type: "object" properties: help_page[name]: type: "string" description: "The unique name identifier for the help page" help_page[wiki_page]: type: "string" description: "The wiki page title to link to" help_page[related]: type: "string" description: "Comma-separated related help page names" help_page[title]: type: "string" description: "The display title for the help page" GetEmailBlacklistsSearchOrder: type: "string" enum: - "reason" - "domain" CreateEmailBlacklistBody: type: "object" required: - "email_blacklist[domain]" - "email_blacklist[reason]" properties: email_blacklist[domain]: type: "string" description: "The email domain to blacklist" email_blacklist[reason]: type: "string" description: "The reason for blacklisting" OpenidConfiguration: type: "object" description: "OpenID Connect provider metadata. Members whose value is null are omitted." required: - "issuer" - "authorization_endpoint" - "token_endpoint" - "revocation_endpoint" - "userinfo_endpoint" - "jwks_uri" - "scopes_supported" - "response_types_supported" - "response_modes_supported" - "grant_types_supported" - "token_endpoint_auth_methods_supported" - "subject_types_supported" - "id_token_signing_alg_values_supported" - "claim_types_supported" - "claims_supported" properties: issuer: type: "string" description: "The issuer identifier" authorization_endpoint: type: "string" description: "The authorization endpoint URL" token_endpoint: type: "string" description: "The token endpoint URL" revocation_endpoint: type: "string" description: "The token revocation endpoint URL" introspection_endpoint: type: "string" description: "The token introspection endpoint URL" userinfo_endpoint: type: "string" description: "The userinfo endpoint URL" jwks_uri: type: "string" description: "The JSON Web Key Set URL" end_session_endpoint: type: "string" nullable: true description: "The RP-initiated logout endpoint, when one is configured" registration_endpoint: type: "string" description: "The dynamic client registration endpoint, present only when dynamic registration is enabled" scopes_supported: type: "array" description: "The scopes the provider accepts" items: $ref: "#/components/schemas/OauthScope" response_types_supported: type: "array" description: "The authorization response types the provider supports" items: type: "string" response_modes_supported: type: "array" description: "The response modes the provider supports" items: type: "string" grant_types_supported: type: "array" description: "The grant types the provider supports" items: type: "string" token_endpoint_auth_methods_supported: type: "array" description: "The client authentication methods the token endpoint accepts" items: type: "string" subject_types_supported: type: "array" description: "The subject identifier types the provider supports" items: type: "string" id_token_signing_alg_values_supported: type: "array" description: "The signing algorithms the provider uses for ID tokens" items: type: "string" claim_types_supported: type: "array" description: "The claim types the provider supports" items: type: "string" claims_supported: type: "array" description: "The claims the provider can return, being the standard claims plus those configured by the site" items: type: "string" code_challenge_methods_supported: type: "array" description: "The PKCE code challenge methods the provider accepts" items: type: "string" OauthScope: type: "string" description: "An OAuth scope. `openid` is the default scope. The rest are optional." enum: - "openid" - "profile" - "email" - "full" Webfinger: type: "object" required: - "subject" - "links" properties: subject: type: "string" description: "The resource that was requested" links: type: "array" description: "The links describing the resource" items: $ref: "#/components/schemas/WebfingerLink" WebfingerLink: type: "object" required: - "rel" - "href" properties: rel: type: "string" description: "The relation type, always `http://openid.net/specs/connect/1.0/issuer`" href: type: "string" description: "The issuer identifier" Jwks: type: "object" required: - "keys" properties: keys: type: "array" description: "The public keys in JWK form" items: type: "object" additionalProperties: true Userinfo: type: "object" description: | OpenID Connect claims for the authenticated user. `sub` is always present. The remaining claims depend on the scopes granted to the token. required: - "sub" properties: sub: type: "integer" description: "The user ID" preferred_username: type: "string" description: "The account name" name: type: "string" description: "The account name" picture: type: "string" nullable: true description: "The avatar URL, or null when the user has no usable avatar" updated_at: type: "integer" description: "When the account was last updated, as a Unix timestamp" e621_level: type: "integer" description: "The numeric user level" e621_level_string: type: "string" description: "The display name of the user level, such as `Member` or `Janitor`" e621_avatar_id: type: "integer" nullable: true description: "The post ID used as the account avatar" e621_permissions: type: "array" description: | The permission flags the user holds. Contains `is_` for the user's level and any capability flags such as `can_approve_posts`. items: type: "string" email: type: "string" description: "The account email address" email_verified: type: "boolean" description: "Whether the account email address is present and verified" CreateOauthTokenBody: type: "object" required: - "grant_type" - "client_id" properties: grant_type: type: "string" description: "The grant type. `authorization_code` is the only enabled flow, and `refresh_token` may be used to renew a token." enum: - "authorization_code" - "refresh_token" client_id: type: "string" description: "The application's client identifier" client_secret: type: "string" description: "The application's client secret, for confidential clients" code: type: "string" description: "The authorization code, for `grant_type=authorization_code`" redirect_uri: type: "string" description: "The redirect URI used in the authorization request" code_verifier: type: "string" description: "The PKCE code verifier. Required, since PKCE is enforced." refresh_token: type: "string" description: "The refresh token, for `grant_type=refresh_token`" OauthToken: type: "object" required: - "access_token" - "token_type" - "expires_in" - "created_at" properties: access_token: type: "string" description: "The issued access token" token_type: type: "string" description: "The token type, `Bearer`" expires_in: type: "integer" description: "The token lifetime in seconds" refresh_token: type: "string" description: "The refresh token, when one was issued" scope: type: "string" description: "The granted scopes, space separated" created_at: type: "integer" description: "When the token was issued, as a Unix timestamp" id_token: type: "string" description: "The ID token, when the `openid` scope was granted" RevokeOauthTokenBody: type: "object" required: - "token" properties: token: type: "string" description: "The access or refresh token to revoke" client_id: type: "string" description: "The application's client identifier" client_secret: type: "string" description: "The application's client secret" IntrospectOauthTokenBody: type: "object" required: - "token" properties: token: type: "string" description: "The token to introspect" client_id: type: "string" description: "The application's client identifier" client_secret: type: "string" description: "The application's client secret" OauthTokenIntrospection: type: "object" required: - "active" properties: active: type: "boolean" description: "Whether the token is currently valid" scope: type: "string" description: "The granted scopes, space separated" client_id: type: "string" description: "The client the token was issued to" token_type: type: "string" description: "The token type, `Bearer`" iat: type: "integer" description: "When the token was issued, as a Unix timestamp" exp: type: "integer" description: "When the token expires, as a Unix timestamp. Omitted for tokens that do not expire." OauthTokenInfo: type: "object" required: - "resource_owner_id" - "scope" - "expires_in" - "created_at" properties: resource_owner_id: type: "integer" description: "The ID of the user who owns the token" scope: type: "array" description: "The granted scopes" items: type: "string" expires_in: type: "integer" nullable: true description: "Seconds until the token expires" application: type: "object" description: "The application the token was issued to" properties: uid: type: "string" description: "The application's client identifier" created_at: type: "integer" description: "When the token was issued, as a Unix timestamp" DbExport: type: "object" description: "A database export file offered for download." required: - "name" - "file_name" - "file_size" - "updated_at" - "url" properties: name: type: "string" description: "The export name, such as the table it was taken from" file_name: type: "string" description: "The file name, being the export name followed by `.csv.gz`" file_size: type: "integer" description: "The size of the export file in bytes" checksum: type: "string" nullable: true description: "The checksum of the export file" updated_at: type: "string" format: "date-time" description: "The time when the export was last written" url: type: "string" description: "The URL the export can be downloaded from" UserAvatarMenu: type: "object" description: "Which of the current user's content listings are non-empty." required: - "has_uploads" - "has_favorites" - "has_sets" - "has_comments" - "has_forums" - "has_blips" properties: has_uploads: type: "boolean" description: "Whether the user has uploaded any posts" has_favorites: type: "boolean" description: "Whether the user has any favorites" has_sets: type: "boolean" description: "Whether the user owns any post sets" has_comments: type: "boolean" description: "Whether the user has posted any comments" has_forums: type: "boolean" description: "Whether the user has posted in the forums" has_blips: type: "boolean" description: "Whether the user has posted any blips" UserUploadTags: type: "object" description: "Tag suggestions for the upload tag editor." required: - "upload_tags" - "recent_tags" properties: upload_tags: type: "array" description: "The user's favorite tags, in the order they configured them" items: $ref: "#/components/schemas/UserUploadTag" recent_tags: type: "array" description: "Up to 50 tags the user added to posts in the last hour, most used first" items: $ref: "#/components/schemas/UserUploadTag" UserUploadTag: type: "object" description: "A tag suggestion with its post count and category." required: - "name" - "count" - "category_id" properties: name: type: "string" description: "The tag name" count: type: "integer" description: "The number of posts carrying the tag" category_id: type: "integer" description: "The tag's category ID" StaffUserAltListEntry: type: "array" description: "The user's ID followed by the IDs of accounts sharing their last-seen IP address." items: oneOf: - type: "integer" description: "The user's ID" - type: "array" description: "The IDs of suspected alt accounts" items: type: "integer" UserAlt: type: "object" description: "A suspected alt account, scored on shared-network evidence. Carries no IP or subnet value." required: - "user_id" - "score" - "handoff" - "handoff_users" - "shared_exact" - "shared_subnet" - "total_ips" - "ratio" - "rarest_users" - "overlap_first" - "overlap_last" - "last_co_seen" - "concurrent" - "deleted" - "user" properties: user_id: type: "integer" description: "The ID of the candidate account" score: type: "number" format: "float" description: "Confidence score from 0 to 100, rounded to one decimal place" handoff: type: "boolean" description: "Whether a shared IP appears to have been handed over from one account to the other" handoff_users: type: "integer" nullable: true description: "How many distinct accounts were seen on the IP that triggered the handoff, or null when there was no handoff" shared_exact: type: "integer" description: "Number of exact IP addresses shared with the target" shared_subnet: type: "integer" description: "Number of subnets shared with the target, excluding those already counted as exact matches" total_ips: type: "integer" description: "Number of IP addresses recorded for the candidate in the retention window" ratio: type: "number" format: "float" description: "Fraction of the candidate's IP addresses that are shared with the target" rarest_users: type: "integer" description: "The smallest number of distinct accounts seen on any of the shared values" overlap_first: type: "string" format: "date-time" description: "Earliest activity on a shared value across both accounts" overlap_last: type: "string" format: "date-time" description: "Latest activity on a shared value across both accounts" last_co_seen: type: "string" format: "date-time" description: "The most recent time both accounts were still active on the same shared value" concurrent: type: "boolean" description: "Whether the two accounts' activity windows on a shared value actually overlapped" deleted: type: "boolean" description: "Whether the candidate account has been anonymized" user: $ref: "#/components/schemas/UserAltUser" UserAltUser: type: "object" description: "The identifying fields of a suspected alt account." required: - "id" - "name" - "level_string" - "created_at" properties: id: type: "integer" description: "The unique ID of the user" name: type: "string" description: "The username of the user" level_string: type: "string" description: "The user's access level (textual description)" created_at: type: "string" format: "date-time" description: "The timestamp when the user account was created" UpdateStaffUserBody: type: "object" required: - "user" properties: user: $ref: "#/components/schemas/UpdateStaffUserBodyUser" UpdateStaffUserBodyUser: type: "object" properties: name: type: "string" description: "A new username; a value differing from the current one files an administrative name change request" email: type: "string" description: "A new email address. Only accepted from BD staff" profile_about: type: "string" description: "The user's \"About\" profile section" profile_artinfo: type: "string" description: "The user's art information profile section" base_upload_limit: type: "integer" description: "The base upload limit for the user" enable_privacy_mode: type: "boolean" description: "Whether the user's activity is hidden from other users" custom_title: type: "string" description: "The title shown beside the user's name" upload_karma: type: "integer" description: "The user's upload karma; the difference from the current value is applied as a staff override" verified: type: "boolean" description: "Whether the account is email-verified. Only honoured for BD staff" level: type: "integer" description: "The user's new access level (0 Anonymous, 10 Blocked, 20 Member, 30 Privileged, 40 Former Staff, 50 Staff, 60 Janitor, 70 Moderator, 80 Admin)" can_approve_posts: type: "boolean" description: "Whether the user may approve posts. Only applied when `level` is also sent" can_upload_free: type: "boolean" description: "Whether the user bypasses the upload queue. Only applied when `level` is also sent" tag_warden: type: "boolean" description: "Whether the user holds the tag warden flag. Only applied when `level` is also sent" no_flagging: type: "boolean" description: "Whether the user is barred from flagging posts. Only applied when `level` is also sent" replacements_beta: type: "boolean" description: "Whether the user may use the replacements beta. Only applied when `level` is also sent" raised_favorite_limit: type: "boolean" description: "Whether the user has a raised favorite limit. Only applied when `level` is also sent" UpdateStaffUserBlacklistBody: type: "object" required: - "user" properties: user: $ref: "#/components/schemas/UpdateStaffUserBlacklistBodyUser" UpdateStaffUserBlacklistBodyUser: type: "object" required: - "blacklisted_tags" properties: blacklisted_tags: type: "string" description: "The replacement blacklist, one entry per line" AnonymizeStaffUserBody: type: "object" properties: password: type: "string" description: "Read by the server but unused: password verification is skipped for administrative deletions" UpdateStaffNoteBody: type: "object" required: - "staff_note" properties: staff_note: $ref: "#/components/schemas/UpdateStaffNoteBodyStaffNote" UpdateStaffNoteBodyStaffNote: type: "object" properties: body: type: "string" description: "The new body text of the staff note" CreateUserFeedbackBody: type: "object" required: - "user_feedback" properties: user_feedback: $ref: "#/components/schemas/CreateUserFeedbackBodyUserFeedback" CreateUserFeedbackBodyUserFeedback: type: "object" required: - "body" - "category" properties: body: type: "string" description: "The feedback body (DText supported)" category: $ref: "#/components/schemas/UserFeedbackCategory" user_id: type: "integer" description: "The ID of the user the feedback is about" user_name: type: "string" description: "The username of the user the feedback is about, as an alternative to `user_id`" CreateUserNameChangeRequestBody: type: "object" required: - "user_name_change_request" properties: user_name_change_request: $ref: "#/components/schemas/CreateUserNameChangeRequestBodyUserNameChangeRequest" CreateUserNameChangeRequestBodyUserNameChangeRequest: type: "object" required: - "desired_name" properties: desired_name: type: "string" description: "The requested new username" change_reason: type: "string" description: "The reason for the name change" UpdateDmailFilterBody: type: "object" required: - "dmail_filter" properties: dmail_filter: $ref: "#/components/schemas/UpdateDmailFilterBodyDmailFilter" UpdateDmailFilterBodyDmailFilter: type: "object" required: - "words" properties: words: type: "string" description: "The filter word list, one entry per line" PostCount: type: "object" description: "An approximate count of the posts matching a tag search." required: - "count" - "capped" properties: count: type: "integer" description: "The number of matching posts, up to the cap" capped: type: "boolean" description: "Whether the count hit the cap and is only a lower bound" PostRecommendations: type: "object" description: "Posts recommended for a given post." required: - "post_id" - "model_version" - "results" - "post_data" properties: post_id: type: "integer" description: "The ID of the post the recommendations were made for" model_version: type: "string" description: "The recommendation model that produced the results (e.g. \"os.artist\", \"os.tags\")" results: type: "array" items: $ref: "#/components/schemas/PostRecommendationResult" description: "The recommended post IDs with their scores" post_data: type: "array" items: $ref: "#/components/schemas/ThumbnailPost" description: "Thumbnail payloads for the recommended posts" PostRecommendationResult: type: "object" required: - "post_id" - "score" - "explanation" properties: post_id: type: "integer" description: "The ID of the recommended post" score: type: "number" description: "The recommendation score" explanation: type: "string" nullable: true description: "An explanation of the recommendation, if the model provided one" StaffPostPreviousOwner: type: "object" description: "A user who previously owned a post." required: - "id" - "name" properties: id: type: "integer" description: "The user's ID" name: type: "string" description: "The user's username" UploadKarmaEvent: type: "object" description: "A single row of the upload karma ledger." required: - "id" - "user_id" - "creator_id" - "post_id" - "reason" - "delta" - "balance" - "extra_data" - "created_at" properties: id: type: "integer" description: "The unique ID of the event" user_id: type: "integer" description: "The ID of the user whose karma changed" creator_id: type: "integer" description: "The ID of the user who caused the change" post_id: type: "integer" nullable: true description: "The ID of the post the change relates to, if any" reason: $ref: "#/components/schemas/UploadKarmaEventReason" delta: type: "integer" description: "The karma added or removed by this event" balance: type: "integer" description: "The user's karma balance after this event" extra_data: type: "object" additionalProperties: true description: "Reason-specific detail attached to the event" created_at: type: "string" format: "date-time" description: "When the event was recorded" UploadKarmaEventReason: type: "string" description: "Why an upload karma event was recorded" enum: - "approved" - "unapproved" - "deleted" - "undeleted" - "replacement_penalty" - "replacement_penalty_reversed" - "replacement_transfer" - "owner_change" - "staff_override" - "queue_bypass" GetUploadKarmaEventsSearchOrder: type: "string" enum: - "id_asc" - "id_desc" UpdatePostBody: type: "object" required: - "post" properties: post: $ref: "#/components/schemas/UpdatePostBodyPost" UpdatePostBodyPost: type: "object" properties: tag_string: type: "string" description: "The complete new tag string. Ignored when `tag_string_diff` is present." old_tag_string: type: "string" description: "The tag string the edit was based on, used for conflict detection" tag_string_diff: type: "string" description: "Tags to add and remove, with removals prefixed by `-`" source_diff: type: "string" description: "Sources to add and remove, with removals prefixed by `-`" parent_id: type: "integer" description: "The ID of the parent post" old_parent_id: type: "integer" description: "The parent ID the edit was based on, used for conflict detection" source: type: "string" description: "The complete new source list, newline separated. Ignored when `source_diff` is present." old_source: type: "string" description: "The source list the edit was based on, used for conflict detection" description: type: "string" description: "The post description" old_description: type: "string" description: "The description the edit was based on, used for conflict detection" rating: $ref: "#/components/schemas/PostRating" old_rating: $ref: "#/components/schemas/PostRating" edit_reason: type: "string" description: "The reason recorded for this edit" is_rating_locked: type: "boolean" description: "Whether the rating is locked. Must be Privileged+ to send." is_note_locked: type: "boolean" description: "Whether notes are locked. Must be Staff+ to send." bg_color: type: "string" description: "The post's background colour. Must be Staff+ to send." is_comment_locked: type: "boolean" description: "Whether commenting is locked. Must be Moderator+ to send." is_status_locked: type: "boolean" description: "Whether the post status is locked. Must be Admin+ to send." is_comment_disabled: type: "boolean" description: "Whether comments are hidden. Must be Admin+ to send." locked_tags: type: "string" description: "Tags that cannot be removed. Must be Admin+ to send." hide_from_anonymous: type: "boolean" description: "Whether the post is hidden from anonymous visitors. Must be Admin+ to send." hide_from_search_engines: type: "boolean" description: "Whether the post is hidden from search engines. Must be Admin+ to send." hide_favorites_list: type: "boolean" description: "Whether the post's favorites list is hidden. Must be Admin+ to send." MarkPostAsTranslatedBody: type: "object" required: - "post" properties: post: $ref: "#/components/schemas/MarkPostAsTranslatedBodyPost" MarkPostAsTranslatedBodyPost: type: "object" properties: translation_check: type: "boolean" description: "Adds or removes the `translation_check` tag" partially_translated: type: "boolean" description: "Adds or removes the `partially_translated` tag" StaffReownerPostBody: type: "object" required: - "reowner" properties: reowner: $ref: "#/components/schemas/StaffReownerPostBodyReowner" StaffReownerPostBodyReowner: type: "object" required: - "new_owner" properties: new_owner: type: "string" description: "The new owner, given as a username or as `!`" reowner_versions: type: "boolean" description: "Also reassign the post's versions. Defaults to false." post_events: type: "boolean" description: "Also reassign the post's events. Defaults to true." karma: type: "boolean" description: "Also move the upload karma for the post. Defaults to true." UpdatePostSetPostsBody: type: "object" required: - "post_set" properties: post_set: $ref: "#/components/schemas/UpdatePostSetPostsBodyPostSet" UpdatePostSetPostsBodyPostSet: type: "object" required: - "post_ids_string" properties: post_ids_string: type: "string" description: "The complete desired post ID list. Every run of digits is read as an ID. The set is added to and removed from to match." CreateUploadBody: type: "object" required: - "upload[tag_string]" - "upload[rating]" properties: upload[file]: type: "string" format: "binary" description: "The file to upload. Mutually exclusive with `upload[direct_url]`." upload[direct_url]: type: "string" description: "A URL to fetch the file from. Mutually exclusive with `upload[file]`." upload[source]: type: "string" description: "The source list for the new post, newline separated" upload[tag_string]: type: "string" description: "The tags for the new post" upload[rating]: $ref: "#/components/schemas/PostRating" upload[parent_id]: type: "integer" description: "The ID of the parent post" upload[description]: type: "string" description: "The description for the new post" upload[as_pending]: type: "boolean" description: "Whether to upload the post as pending rather than approved" upload[locked_rating]: type: "boolean" description: "Whether the rating is locked. Must be Privileged+ to send." upload[locked_tags]: type: "string" description: "Tags that cannot be removed. Must be Admin+ to send." UpdateUploadWhitelistBody: type: "object" properties: upload_whitelist[allowed]: type: "boolean" description: "Whether uploads from this domain are allowed" upload_whitelist[domain]: type: "string" description: "The domain pattern" upload_whitelist[path]: type: "string" description: "The path pattern" upload_whitelist[reason]: type: "string" description: "The reason for the whitelist entry" upload_whitelist[note]: type: "string" description: "Note about the whitelist entry" upload_whitelist[hidden]: type: "boolean" description: "Whether the entry is hidden" CreateArtistBody: type: "object" required: - "artist" properties: artist: $ref: "#/components/schemas/CreateArtistBodyArtist" CreateArtistBodyArtist: type: "object" properties: name: type: "string" description: "The artist's tag name" other_names: type: "string" description: "Space-separated alternative names for the artist" other_names_string: type: "string" description: "Space-separated alternative names for the artist" group_name: type: "string" description: "The name of the artist group or circle" url_string: type: "string" description: "Newline-separated artist URLs" notes: type: "string" description: "The body of the artist's wiki page" linked_user_id: type: "integer" description: "The ID of the linked user account (staff only)" is_locked: type: "boolean" description: "Whether the artist page is locked (staff only)" UpdateArtistBody: type: "object" required: - "artist" properties: artist: $ref: "#/components/schemas/UpdateArtistBodyArtist" UpdateArtistBodyArtist: type: "object" properties: name: type: "string" description: "The artist's tag name" other_names: type: "string" description: "Space-separated alternative names for the artist" other_names_string: type: "string" description: "Space-separated alternative names for the artist" group_name: type: "string" description: "The name of the artist group or circle" url_string: type: "string" description: "Newline-separated artist URLs" notes: type: "string" description: "The body of the artist's wiki page" linked_user_id: type: "integer" description: "The ID of the linked user account (staff only)" is_locked: type: "boolean" description: "Whether the artist page is locked (staff only)" CreateTakedownBody: type: "object" required: - "takedown" properties: takedown: $ref: "#/components/schemas/CreateTakedownBodyTakedown" CreateTakedownBodyTakedown: type: "object" required: - "email" - "reason" properties: email: type: "string" description: "The contact email address for the request" source: type: "string" description: "The source the content was taken from" instructions: type: "string" description: "Instructions for handling the request" reason: type: "string" description: "The reason for the takedown" post_ids: type: "string" description: "Post IDs or post URLs to take down; digit runs are extracted from the value" reason_hidden: type: "boolean" description: "Whether the reason is hidden from non-staff" notes: type: "string" description: "Staff notes for the takedown (BD staff only)" del_post_ids: type: "string" description: "Post IDs to mark for deletion (BD staff only)" status: allOf: - $ref: "#/components/schemas/TakedownStatus" description: "The takedown status (BD staff only). A create always overwrites this with \"pending\"." TagCorrection: type: "object" required: - "post_count" - "real_post_count" - "category" - "category_cache" - "tag" properties: post_count: type: "integer" description: "The post count currently stored on the tag" real_post_count: type: "integer" description: "The post count reported by the search index" category: type: "integer" description: "The category ID currently stored on the tag" category_cache: type: "integer" nullable: true description: "The cached category ID for the tag, null when the cache entry has expired" tag: $ref: "#/components/schemas/Tag" UpdateTagAliasBody: type: "object" properties: tag_alias[antecedent_name]: type: "string" description: "The name of the antecedent tag, only applied while the alias is pending" tag_alias[consequent_name]: type: "string" description: "The name of the consequent tag, only applied while the alias is pending" tag_alias[forum_topic_id]: type: "integer" description: "The ID of the forum topic to link to" UpdateTagImplicationBody: type: "object" properties: tag_implication[antecedent_name]: type: "string" description: "The name of the antecedent tag" tag_implication[consequent_name]: type: "string" description: "The name of the consequent tag" tag_implication[forum_topic_id]: type: "integer" description: "The ID of the forum topic to link to" CreateTagCorrectionBody: type: "object" properties: commit: type: "string" enum: - "Fix" description: "Must be Fix for the correction to be queued" from_wiki: type: "boolean" description: "Redirect to the tag's wiki page instead of the tag search" StaffWiki: type: "object" description: "A staff-only wiki page." required: - "id" - "creator_id" - "updater_id" - "title" - "body" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the staff wiki page" creator_id: type: "integer" description: "The ID of the user who created the page" updater_id: type: "integer" description: "The ID of the user who last updated the page" claimant_id: type: "integer" nullable: true description: "The ID of the user currently claiming the page" title: type: "string" description: "The title of the page" body: type: "string" description: "The DText body of the page" created_at: type: "string" format: "date-time" description: "When the page was created" updated_at: type: "string" format: "date-time" description: "When the page was last updated" StaffWikiVersion: type: "object" description: "A past revision of a staff wiki page." required: - "id" - "staff_wiki_id" - "updater_id" - "title" - "body" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the version" staff_wiki_id: type: "integer" description: "The ID of the staff wiki page this version belongs to" updater_id: type: "integer" description: "The ID of the user who made the edit" claimant_id: type: "integer" nullable: true description: "The ID of the user claiming the page at the time of the edit" title: type: "string" description: "The title of the page in this version" body: type: "string" description: "The DText body of the page in this version" created_at: type: "string" format: "date-time" description: "When the version was created" updated_at: type: "string" format: "date-time" description: "When the version was last updated" StaffFile: type: "object" description: "A file uploaded to the staff file store." required: - "id" - "creator_id" - "storage_id" - "md5" - "file_ext" - "file_size" - "original_filename" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the staff file" creator_id: type: "integer" description: "The ID of the user who uploaded the file" storage_id: type: "string" description: "The random identifier the file is stored under" md5: type: "string" description: "The MD5 hash of the file contents" file_ext: type: "string" description: "The file extension, lowercased, with `jpeg` normalized to `jpg`" file_size: type: "integer" description: "The size of the file in bytes" original_filename: type: "string" description: "The filename the file was uploaded under" title: type: "string" nullable: true description: "The display title, defaulting to the original filename" description: type: "string" nullable: true description: "A free-text description of the file" created_at: type: "string" format: "date-time" description: "When the file was uploaded" updated_at: type: "string" format: "date-time" description: "When the file record was last updated" ExceptionLog: type: "object" description: "A recorded server exception." required: - "id" - "class_name" - "version" - "message" - "trace" - "code" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the exception log" class_name: type: "string" description: "The class name of the raised exception" version: type: "string" description: "The application version the exception was raised on" message: type: "string" description: "The exception message" trace: type: "string" description: "The newline-separated backtrace" code: type: "string" format: "uuid" description: "The public code shown to the user who hit the error" extra_params: type: "object" nullable: true description: "Request context captured with the exception, including the host, filtered request params, referrer and user agent" user_id: type: "integer" nullable: true description: "The ID of the user whose request raised the exception" created_at: type: "string" format: "date-time" description: "When the exception was recorded" updated_at: type: "string" format: "date-time" description: "When the exception log was last updated" GetStaffWikisSearchOrder: type: "string" enum: - "title" - "id_asc" - "id_desc" GetStaffFilesSearchOrder: type: "string" enum: - "original_filename" - "time" - "id_asc" - "id_desc" GetExceptionLogsSearchOrder: type: "string" enum: - "id_asc" - "id_desc" CreateStaffWikiBody: type: "object" required: - "staff_wiki" properties: staff_wiki: $ref: "#/components/schemas/CreateStaffWikiBodyStaffWiki" CreateStaffWikiBodyStaffWiki: type: "object" required: - "title" properties: title: type: "string" minLength: 1 maxLength: 100 description: "The title of the page, which must be unique" body: type: "string" description: "The DText body of the page" related_type: $ref: "#/components/schemas/StaffWikiRefType" related_id: type: "integer" description: "The ID of the record to reference, of the type given by `related_type`" UpdateStaffWikiBody: type: "object" required: - "staff_wiki" properties: staff_wiki: $ref: "#/components/schemas/UpdateStaffWikiBodyStaffWiki" UpdateStaffWikiBodyStaffWiki: type: "object" properties: title: type: "string" minLength: 1 maxLength: 100 description: "The title of the page" body: type: "string" description: "The DText body of the page" StaffWikiRefType: type: "string" enum: - "User" - "Artist" - "StaffWiki" description: "The kind of record a staff wiki page reference points at" CreateStaffFileBody: type: "object" required: - "staff_file[file]" properties: staff_file[file]: type: "string" format: "binary" description: "The file to upload" staff_file[title]: type: "string" description: "The display title, defaulting to the uploaded filename" staff_file[description]: type: "string" description: "A free-text description of the file" UpdateStaffFileBody: type: "object" required: - "staff_file" properties: staff_file: $ref: "#/components/schemas/UpdateStaffFileBodyStaffFile" UpdateStaffFileBodyStaffFile: type: "object" properties: title: type: "string" description: "The display title. Cleared titles fall back to the original filename." description: type: "string" description: "A free-text description of the file" SearchTrend: type: "object" description: "The number of times a tag was searched for on a given day." required: - "tag" - "count" - "day" properties: tag: type: "string" description: "The tag name" count: type: "integer" description: "The number of searches recorded for the day" day: type: "string" format: "date" description: "The day the searches were recorded on" SearchTrendPoint: type: "object" description: "One day of a tag's search history." required: - "count" - "day" properties: count: type: "integer" description: "The number of searches recorded for the day" day: type: "string" format: "date" description: "The day the searches were recorded on" RisingSearchTrend: type: "object" description: "A tag whose search volume rose sharply in the last 24 hours." required: - "name" - "pretty_name" - "post_count" - "category" properties: name: type: "string" description: "The tag name" pretty_name: type: "string" description: "The tag name with underscores replaced by spaces" post_count: type: "integer" description: "The number of posts with this tag, or 0 if the tag does not exist" category: type: "integer" description: "The tag category, or 0 if the tag does not exist" SearchTrendPurgeResult: type: "object" description: "The number of search trend records deleted by a purge." required: - "daily_count" - "hourly_count" properties: daily_count: type: "integer" description: "The number of daily records deleted" hourly_count: type: "integer" description: "The number of hourly records deleted" SearchTrendSettingsResult: type: "object" description: "The outcome of a search trend settings or cache operation." required: - "success" - "message" properties: success: type: "boolean" description: "Always true" message: type: "string" description: "A human readable description of what was done" UpdateSearchTrendSettingsBody: type: "object" properties: search_trend_settings: $ref: "#/components/schemas/UpdateSearchTrendSettingsBodySearchTrendSettings" UpdateSearchTrendSettingsBodySearchTrendSettings: type: "object" properties: trends_enabled: type: "boolean" description: "Whether search trend recording is enabled" trends_displayed: type: "boolean" description: "Whether search trends are displayed on the site" trends_min_today: type: "integer" description: "The minimum number of searches in the current window for a tag to be rising" trends_min_delta: type: "integer" description: "The minimum increase over the previous window for a tag to be rising" trends_min_ratio: type: "number" description: "The minimum ratio between the current and previous window for a tag to be rising" trends_ip_limit: type: "integer" description: "The number of recordings allowed per IP address within the IP window" trends_ip_window: type: "integer" description: "The IP rate limit window, in seconds" trends_tag_limit: type: "integer" description: "The number of recordings allowed per tag within the tag window" trends_tag_window: type: "integer" description: "The tag rate limit window, in seconds" SearchTrendHourly: type: "object" description: "The number of times a tag was searched for during a given hour." required: - "tag" - "count" - "hour" - "processed" properties: tag: type: "string" description: "The tag name" count: type: "integer" description: "The number of searches recorded for the hour" hour: type: "string" format: "date-time" description: "The start of the hour the searches were recorded in" processed: type: "boolean" description: "Whether the record has been rolled up into the daily totals" SearchTrendBlacklist: type: "object" description: "A tag pattern excluded from search trend recording." required: - "id" - "tag" - "reason" - "creator_id" - "created_at" - "updated_at" properties: id: type: "integer" description: "The unique ID of the blacklist entry" tag: type: "string" description: "The blacklisted tag pattern, supporting the `*` and `?` globs" reason: type: "string" description: "The reason for blacklisting" creator_id: type: "integer" description: "The ID of the user who created the entry" created_at: type: "string" format: "date-time" description: "When the entry was created" updated_at: type: "string" format: "date-time" description: "When the entry was last updated" GetSearchTrendBlacklistsSearchOrder: type: "string" enum: - "id_asc" - "id_desc" CreateSearchTrendBlacklistBody: type: "object" required: - "search_trend_blacklist" properties: search_trend_blacklist: $ref: "#/components/schemas/CreateSearchTrendBlacklistBodySearchTrendBlacklist" CreateSearchTrendBlacklistBodySearchTrendBlacklist: type: "object" required: - "tag" properties: tag: type: "string" description: "The tag pattern to blacklist. A bare `*` is rejected." reason: type: "string" description: "The reason for blacklisting" UpdateSearchTrendBlacklistBody: type: "object" required: - "search_trend_blacklist" properties: search_trend_blacklist: $ref: "#/components/schemas/UpdateSearchTrendBlacklistBodySearchTrendBlacklist" UpdateSearchTrendBlacklistBodySearchTrendBlacklist: type: "object" properties: tag: type: "string" description: "The tag pattern to blacklist. A bare `*` is rejected." reason: type: "string" description: "The reason for blacklisting" Stats: type: "object" description: "A snapshot of site-wide statistics. Empty until the snapshot job has run." properties: started: type: "string" format: "date-time" description: "When the oldest post was created" total_posts: type: "integer" description: "The highest post ID" active_posts: type: "integer" description: "The number of active posts" deleted_posts: type: "integer" description: "The number of deleted posts" existing_posts: type: "integer" description: "The sum of active and deleted posts" destroyed_posts: type: "integer" description: "The number of posts that no longer exist" total_votes: type: "integer" description: "The number of post votes" total_notes: type: "integer" description: "The number of notes" total_favorites: type: "integer" description: "The number of favorites" total_pools: type: "integer" description: "The number of pools" public_sets: type: "integer" description: "The number of public post sets" private_sets: type: "integer" description: "The number of private post sets" total_sets: type: "integer" description: "The sum of public and private post sets" average_posts_per_pool: type: "number" description: "The average number of posts in a pool" average_posts_per_set: type: "number" description: "The average number of posts in a post set" safe_posts: type: "integer" description: "The number of safe rated posts" questionable_posts: type: "integer" description: "The number of questionable rated posts" explicit_posts: type: "integer" description: "The number of explicit rated posts" jpg_posts: type: "integer" description: "The number of JPEG posts" png_posts: type: "integer" description: "The number of PNG posts" webp_posts: type: "integer" description: "The number of WebP posts" gif_posts: type: "integer" description: "The number of GIF posts" swf_posts: type: "integer" description: "The number of SWF posts" webm_posts: type: "integer" description: "The number of WebM posts" mp4_posts: type: "integer" description: "The number of MP4 posts" average_file_size: type: "number" description: "The average post file size, in bytes" total_file_size: type: "integer" description: "The combined size of all post files, in bytes" average_posts_per_day: type: "integer" description: "The average number of posts uploaded per day" total_users: type: "integer" description: "The number of users" anonymous_users: type: "integer" description: "The number of users at the Anonymous level" blocked_users: type: "integer" description: "The number of users at the Blocked level" member_users: type: "integer" description: "The number of users at the Member level" privileged_users: type: "integer" description: "The number of users at the Privileged level" former_staff_users: type: "integer" description: "The number of users at the Former Staff level" staff_users: type: "integer" description: "The number of users at the Staff level" janitor_users: type: "integer" description: "The number of users at the Janitor level" moderator_users: type: "integer" description: "The number of users at the Moderator level" admin_users: type: "integer" description: "The number of users at the Admin level" unactivated_users: type: "integer" description: "The number of users who have not verified their email" total_dmails: type: "integer" description: "The highest DMail ID halved, since each DMail is stored twice" average_registrations_per_day: type: "integer" description: "The average number of accounts registered per day" active_users: type: "integer" description: "The number of users who logged in within the last three months" total_comments: type: "integer" description: "The highest comment ID" active_comments: type: "integer" description: "The number of visible comments" hidden_comments: type: "integer" description: "The number of hidden comments" deleted_comments: type: "integer" description: "The number of comments that no longer exist" average_comments_per_day: type: "integer" description: "The average number of comments posted per day" total_forum_threads: type: "integer" description: "The number of forum topics" total_forum_posts: type: "integer" description: "The highest forum post ID" average_posts_per_thread: type: "integer" description: "The average number of posts in a forum topic" average_forum_posts_per_day: type: "integer" description: "The average number of forum posts made per day" total_blips: type: "integer" description: "The highest blip ID" active_blips: type: "integer" description: "The number of visible blips" deleted_blips: type: "integer" description: "The number of deleted blips" destroyed_blips: type: "integer" description: "The number of blips that no longer exist" average_blips_per_day: type: "integer" description: "The average number of blips posted per day" total_tags: type: "integer" description: "The number of tags" general_tags: type: "integer" description: "The number of general tags" species_tags: type: "integer" description: "The number of species tags" character_tags: type: "integer" description: "The number of character tags" copyright_tags: type: "integer" description: "The number of copyright tags" artist_tags: type: "integer" description: "The number of artist tags" contributor_tags: type: "integer" description: "The number of contributor tags" invalid_tags: type: "integer" description: "The number of invalid tags" lore_tags: type: "integer" description: "The number of lore tags" meta_tags: type: "integer" description: "The number of meta tags" updated_at: type: "string" format: "date-time" description: "When the snapshot was generated"