{
  "openapi": "3.1.0",
  "info": {
    "title": "Moekura API",
    "description": "Read and change a Moekura site: search and upload posts, edit tags, moderate. Responses are JSON; errors look like `{\"error\": {\"status\": 404, \"message\": \"Not found\"}}`.\n\nSend an API key (created in your account settings) as `Authorization: Bearer <key>`. Without one, requests are made as a logged-out visitor and can do what visitors can on the site.",
    "license": {
      "name": "AGPL-3.0-only",
      "identifier": "AGPL-3.0-only"
    },
    "version": "0.4.0"
  },
  "servers": [
    {
      "url": "/api/v1"
    }
  ],
  "paths": {
    "/bans": {
      "get": {
        "tags": [
          "moderation"
        ],
        "summary": "List active bans.",
        "description": "Needs `ban_users`.",
        "operationId": "list_bans",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BanList"
                }
              }
            }
          },
          "403": {
            "description": "You can't ban users",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/comments": {
      "get": {
        "tags": [
          "comments"
        ],
        "summary": "List comments.",
        "description": "Newest first, 50 at a time, on posts you can see. Needs `view_posts`.",
        "operationId": "list_comments",
        "parameters": [
          {
            "name": "post_id",
            "in": "query",
            "description": "Only comments on this post.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Only comments by this user (a name).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Only comments older than this one, for the next page.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentList"
                }
              }
            }
          },
          "404": {
            "description": "No such user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/comments/{id}": {
      "get": {
        "tags": [
          "comments"
        ],
        "summary": "Get a comment.",
        "description": "Needs `view_posts`.",
        "operationId": "get_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Comment number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiComment"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "comments"
        ],
        "summary": "Change your comment.",
        "description": "Needs `comment`; only the author changes a comment.",
        "operationId": "update_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Comment number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentText"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiComment"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "comments"
        ],
        "summary": "Delete your comment.",
        "description": "Needs `comment`; only the author deletes a comment this way (staff\nhide it instead).",
        "operationId": "delete_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Comment number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/comments/{id}/hide": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Hide a comment.",
        "description": "Needs `moderate_comments`. Upholds the comment's open reports; logged.",
        "operationId": "hide_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Comment number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiComment"
                }
              }
            }
          },
          "400": {
            "description": "Already hidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/comments/{id}/report": {
      "post": {
        "tags": [
          "comments"
        ],
        "summary": "Report a comment.",
        "description": "Needs `flag`. Staff find reported comments under Moderation.",
        "operationId": "report_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Comment number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "No reason, or already reported",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/comments/{id}/restore": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Restore a hidden or deleted comment.",
        "description": "Needs `moderate_comments`; logged.",
        "operationId": "restore_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Comment number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiComment"
                }
              }
            }
          },
          "400": {
            "description": "Not hidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/comments/{id}/vote": {
      "put": {
        "tags": [
          "comments"
        ],
        "summary": "Vote on a comment.",
        "description": "Needs `vote`; not on your own comments.",
        "operationId": "vote_on_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Comment number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentVote"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentScore"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/favorite-groups": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "List a user's favorite groups.",
        "description": "Their public groups by name, or all of yours. Needs `view_posts`.",
        "operationId": "list_favorite_groups",
        "parameters": [
          {
            "name": "user",
            "in": "query",
            "description": "Whose groups (a name); yours when left out.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiFavoriteGroup"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Create a favorite group.",
        "description": "Needs `favorite`; at most 100 each.",
        "operationId": "create_favorite_group",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiFavoriteGroupWithPosts"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/favorite-groups/{id}": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "Get a favorite group.",
        "description": "Public groups, and your own private ones. Needs `view_posts`.",
        "operationId": "get_favorite_group",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiFavoriteGroupWithPosts"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "users"
        ],
        "summary": "Change your favorite group.",
        "description": "Fields left out stay as they are.",
        "operationId": "update_favorite_group",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiFavoriteGroupWithPosts"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "users"
        ],
        "summary": "Delete your favorite group.",
        "operationId": "delete_favorite_group",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/favorite-groups/{id}/posts": {
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Add a post to the end of your favorite group.",
        "description": "Adding a post that's already there changes nothing.",
        "operationId": "add_favorite_group_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiFavoriteGroupWithPosts"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/favorite-groups/{id}/posts/{post_id}": {
      "delete": {
        "tags": [
          "users"
        ],
        "summary": "Take a post out of your favorite group.",
        "operationId": "remove_favorite_group_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "post_id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/flags": {
      "get": {
        "tags": [
          "moderation"
        ],
        "summary": "List open flags.",
        "description": "Needs `approve_posts`. The posts whose flags have waited longest, by\npost number, each with its open flags.",
        "operationId": "list_flags",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Posts to return, up to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FlaggedPost"
                  }
                }
              }
            }
          },
          "403": {
            "description": "You can't review flags",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "Get your account.",
        "description": "Needs authentication.",
        "operationId": "get_me",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiMe"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/moderation/log": {
      "get": {
        "tags": [
          "moderation"
        ],
        "summary": "Read the moderation log.",
        "description": "Needs `view_audit_log`.",
        "operationId": "list_mod_actions",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "description": "Only this kind of action (`post.delete`, `user.ban`, …).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "actor",
            "in": "query",
            "description": "Only actions by this user.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "post_id",
            "in": "query",
            "description": "Only actions on this post.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Only actions on this user.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Entries older than this id: a previous page's `next_before`.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/network-bans": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Ban a network.",
        "description": "Needs `ban_users`. Requests from the network can read but not change\nanything, and it can't register or log in.",
        "operationId": "ban_network",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewNetworkBan"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiNetworkBan"
                }
              }
            }
          },
          "400": {
            "description": "The range isn't valid, is too wide, or includes your address",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/network-bans/{id}": {
      "delete": {
        "tags": [
          "moderation"
        ],
        "summary": "Lift a network ban.",
        "description": "Needs `ban_users`.",
        "operationId": "lift_network_ban",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Network ban id",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Lifted"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/notes/{id}": {
      "get": {
        "tags": [
          "notes"
        ],
        "summary": "Get a note.",
        "description": "Needs `view_posts`.",
        "operationId": "get_note",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Note number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiNote"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "notes"
        ],
        "summary": "Change a note.",
        "description": "Needs `edit_notes`. Fields left out stay as they are.",
        "operationId": "update_note",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Note number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NoteChanges"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiNote"
                }
              }
            }
          },
          "409": {
            "description": "The note changed since `base_version`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "notes"
        ],
        "summary": "Delete a note.",
        "description": "Needs `edit_notes`. It stays in the history and can be restored.",
        "operationId": "delete_note",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Note number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "base_version",
            "in": "query",
            "description": "Refuse with 409 if the note changed since this version.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/notes/{id}/versions": {
      "get": {
        "tags": [
          "notes"
        ],
        "summary": "A note's history.",
        "description": "Every version, newest first (at most 500). Needs `view_posts`.",
        "operationId": "list_note_versions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Note number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiNoteVersion"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/pools": {
      "get": {
        "tags": [
          "pools"
        ],
        "summary": "List pools.",
        "description": "Most recently changed first, 50 per page. Needs `view_posts`.",
        "operationId": "list_pools",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "A name prefix, or a pattern with `*` wildcards.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "`series` or `collection`.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "1-based.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PoolList"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "pools"
        ],
        "summary": "Create a pool.",
        "description": "Needs `edit_pools`.",
        "operationId": "create_pool",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewPool"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPoolWithPosts"
                }
              }
            }
          },
          "422": {
            "description": "A bad or taken name, or posts that don't exist",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/pools/{id}": {
      "get": {
        "tags": [
          "pools"
        ],
        "summary": "Get a pool.",
        "description": "Needs `view_posts`.",
        "operationId": "get_pool",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Pool number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPoolWithPosts"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "pools"
        ],
        "summary": "Change a pool.",
        "description": "Needs `edit_pools`. Fields left out stay as they are.",
        "operationId": "update_pool",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Pool number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PoolChanges"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPoolWithPosts"
                }
              }
            }
          },
          "409": {
            "description": "The pool changed since `base_version`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "pools"
        ],
        "summary": "Delete a pool.",
        "description": "Needs `delete_posts`; logged. It can be restored.",
        "operationId": "delete_pool",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Pool number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/pools/{id}/posts": {
      "post": {
        "tags": [
          "pools"
        ],
        "summary": "Add a post to the end of a pool.",
        "description": "Needs `edit_pools`.",
        "operationId": "add_pool_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Pool number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PoolPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPoolWithPosts"
                }
              }
            }
          },
          "422": {
            "description": "Already in the pool, deleted, or the pool is full",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/pools/{id}/restore": {
      "post": {
        "tags": [
          "pools"
        ],
        "summary": "Restore a deleted pool.",
        "description": "Needs `delete_posts`; logged.",
        "operationId": "restore_pool",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Pool number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/pools/{id}/versions": {
      "get": {
        "tags": [
          "pools"
        ],
        "summary": "A pool's history.",
        "description": "Every version, newest first (at most 500). Needs `view_posts`.",
        "operationId": "list_pool_versions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Pool number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiPoolVersion"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts": {
      "get": {
        "tags": [
          "posts"
        ],
        "summary": "Search posts.",
        "description": "Uses the same syntax as the site (see the search help). Blacklists\naren't applied: clients filter as they like. Needs `view_posts`.",
        "operationId": "search_posts",
        "parameters": [
          {
            "name": "tags",
            "in": "query",
            "description": "A search, written as in the site's search box (`cat -dog\nrating:g order:score`).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "A page number, or a cursor from a previous response's `next` or\n`previous`. Cursors keep working however deep the results go;\nnumbered pages stop at the site's limit.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Posts per page, up to the site's maximum. Defaults to the site's\npage size.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostPage"
                }
              }
            }
          },
          "400": {
            "description": "The search or page isn't valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "The site is private: authenticate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "posts"
        ],
        "summary": "Upload a post.",
        "description": "Needs `upload`. The post is `pending` when the site reviews uploads and\nyou lack `upload_without_approval`. Thumbnails are made in the\nbackground: `file.processed` turns true when they're ready.",
        "operationId": "upload_post",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/UploadRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "description": "The new post"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPost"
                }
              }
            }
          },
          "409": {
            "description": "The file was already uploaded; `post_id` names that post",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "413": {
            "description": "The request is larger than the site allows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "A field or the file isn't acceptable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}": {
      "get": {
        "tags": [
          "posts"
        ],
        "summary": "Get a post.",
        "description": "Needs `view_posts`. Pending posts are visible to their uploader and to\nmoderators, deleted ones only to moderators.",
        "operationId": "get_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPost"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "posts"
        ],
        "summary": "Edit a post.",
        "description": "Needs `edit_posts`. Tag changes are applied to the post's tags as they\nare when the change is saved, so edits made meanwhile by others are\nkept. Every change is recorded in the post's history.",
        "operationId": "update_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostChanges"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPost"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "A change isn't acceptable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/approve": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Approve a pending post.",
        "description": "Needs `approve_posts`.",
        "operationId": "approve_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPost"
                }
              }
            }
          },
          "400": {
            "description": "The post isn't pending",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/comments": {
      "post": {
        "tags": [
          "comments"
        ],
        "summary": "Comment on a post.",
        "description": "Needs `comment`. Rate limited; deleted posts can't be commented on.",
        "operationId": "create_comment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentText"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiComment"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "The text is empty or too long, or the post is deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/delete": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Delete a post.",
        "description": "Needs `delete_posts`. Deleted posts stay visible to moderators and can\nbe restored; open flags on the post are upheld.",
        "operationId": "delete_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPost"
                }
              }
            }
          },
          "400": {
            "description": "The post is already deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/favorite": {
      "put": {
        "tags": [
          "posts"
        ],
        "summary": "Favorite a post.",
        "description": "Needs `favorite`. Favoriting twice is harmless.",
        "operationId": "favorite_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reactions"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "posts"
        ],
        "summary": "Unfavorite a post.",
        "description": "Needs `favorite`.",
        "operationId": "unfavorite_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reactions"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/flags": {
      "post": {
        "tags": [
          "posts"
        ],
        "summary": "Flag a post for deletion.",
        "description": "Needs `flag`. Moderators review flags; a post can't have two open flags\nfrom the same user.",
        "operationId": "flag_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewFlag"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Flagged"
          },
          "400": {
            "description": "No reason, or the post can't be flagged now",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/flags/dismiss": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Dismiss a post's flags.",
        "description": "Needs `approve_posts`. The post stays, and is no longer `flagged`.",
        "operationId": "dismiss_flags",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dismissed"
                }
              }
            }
          },
          "400": {
            "description": "The post has no open flags",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/notes": {
      "get": {
        "tags": [
          "notes"
        ],
        "summary": "A post's notes.",
        "description": "Oldest first. Needs `view_posts`.",
        "operationId": "list_post_notes",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "include_deleted",
            "in": "query",
            "description": "Deleted notes too (for those who may edit notes).",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiNote"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "notes"
        ],
        "summary": "Add a note to a post.",
        "description": "Needs `edit_notes`. Not on deleted posts; at most 500 per post.",
        "operationId": "create_note",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewNote"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiNote"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "Empty text, or a box outside the image",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/purge": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Purge a deleted post.",
        "description": "Needs `purge_posts`. The post, its files and its history are removed\nfor good by a background job shortly after.",
        "operationId": "purge_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "The purge is queued"
          },
          "400": {
            "description": "Only deleted posts can be purged",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/reject": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Reject a pending post.",
        "description": "Needs `approve_posts`. The post is deleted.",
        "operationId": "reject_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPost"
                }
              }
            }
          },
          "400": {
            "description": "The post isn't pending",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/restore": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Restore a deleted post.",
        "description": "Needs `delete_posts`.",
        "operationId": "restore_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiPost"
                }
              }
            }
          },
          "400": {
            "description": "The post isn't deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/versions": {
      "get": {
        "tags": [
          "posts"
        ],
        "summary": "List a post's history.",
        "description": "Newest first, at most 500 versions. Needs `view_posts`.",
        "operationId": "list_post_versions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiVersion"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/posts/{id}/vote": {
      "put": {
        "tags": [
          "posts"
        ],
        "summary": "Vote on a post.",
        "description": "Needs `vote`. A new vote replaces your earlier one.",
        "operationId": "vote_on_post",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Post number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Vote"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reactions"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/saved-searches": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "Your saved searches.",
        "description": "By query. Search them together with `search:all` or `search:<label>`.",
        "operationId": "list_saved_searches",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiSavedSearch"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Save a search.",
        "description": "Saving a search you already saved replaces its labels. At most 100.",
        "operationId": "create_saved_search",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SavedSearchInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiSavedSearch"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/saved-searches/{id}": {
      "put": {
        "tags": [
          "users"
        ],
        "summary": "Change a saved search.",
        "operationId": "update_saved_search",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Saved search number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SavedSearchInput"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiSavedSearch"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "users"
        ],
        "summary": "Remove a saved search.",
        "operationId": "delete_saved_search",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Saved search number",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/tag-relations": {
      "get": {
        "tags": [
          "tags"
        ],
        "summary": "List tag aliases or implications.",
        "description": "Newest first, 50 per page. Needs `view_posts`.",
        "operationId": "list_tag_relations",
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "alias",
                "implication"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "active",
                "rejected",
                "deleted"
              ]
            }
          },
          {
            "name": "name",
            "in": "query",
            "description": "Only relations where either tag starts with this.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "1-based.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelationPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "tags"
        ],
        "summary": "Request an alias or implication.",
        "description": "Needs `edit_posts`. Requests wait for someone with `manage_tags`,\nwhose own requests take effect at once; either way the relation is then\napplied to existing posts in the background.",
        "operationId": "request_tag_relation",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewRelation"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiRelation"
                }
              }
            }
          },
          "422": {
            "description": "The tags aren't valid, or the relation would conflict with others",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/tag-relations/{id}": {
      "delete": {
        "tags": [
          "moderation"
        ],
        "summary": "Remove a tag relation.",
        "description": "Ends an active relation (needs `manage_tags`; posts keep their tags),\nor withdraws a pending request (its creator may too).",
        "operationId": "remove_tag_relation",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Relation id",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiRelation"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/tag-relations/{id}/approve": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Approve a tag relation.",
        "description": "Needs `manage_tags`. It's then applied to existing posts in the\nbackground.",
        "operationId": "approve_tag_relation",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Relation id",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiRelation"
                }
              }
            }
          },
          "422": {
            "description": "It isn't pending, or it conflicts with active relations",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/tag-relations/{id}/reject": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Reject a tag relation.",
        "description": "Needs `manage_tags`.",
        "operationId": "reject_tag_relation",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Relation id",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiRelation"
                }
              }
            }
          },
          "422": {
            "description": "It isn't pending",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/tags": {
      "get": {
        "tags": [
          "tags"
        ],
        "summary": "List tags.",
        "description": "50 per page. Needs `view_posts`.",
        "operationId": "list_tags",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "A name prefix, or a pattern with `*` wildcards.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Only tags in this category (`artist`, …).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "count",
                "name",
                "newest"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "1-based.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TagPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/tags/autocomplete": {
      "get": {
        "tags": [
          "tags"
        ],
        "summary": "Suggest tags.",
        "description": "Up to 10 used tags for a prefix, most used first, including tags an\nalias matching the prefix points to, and similarly spelled tags when\nfew match. Needs `view_posts`.",
        "operationId": "autocomplete_tags",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "What has been typed of the tag so far.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Suggestion"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The site is private: authenticate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/tags/{name}": {
      "get": {
        "tags": [
          "tags"
        ],
        "summary": "Get a tag.",
        "description": "Needs `view_posts`.",
        "operationId": "get_tag",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "The tag's name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiTag"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "tags"
        ],
        "summary": "Edit a tag.",
        "description": "Needs `manage_tags`. The change is recorded in the moderation log.",
        "operationId": "update_tag",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "The tag's name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagChanges"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiTag"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "There is no such category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/users/{name}": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "Get a user.",
        "description": "Needs `view_posts`. Only users who can manage users see inactive\naccounts.",
        "operationId": "get_user",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Case-insensitive",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiUser"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/users/{name}/ban": {
      "post": {
        "tags": [
          "moderation"
        ],
        "summary": "Ban a user.",
        "description": "Needs `ban_users` and a role ranked above the user's. Banned users can\nlook around as visitors do, but can't change anything.",
        "operationId": "ban_user",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Case-insensitive",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewBan"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Banned"
          },
          "403": {
            "description": "You can't ban this user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "moderation"
        ],
        "summary": "Lift a user's ban.",
        "description": "Needs `ban_users` and a role ranked above the user's.",
        "operationId": "unban_user",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Case-insensitive",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Lifted"
          },
          "400": {
            "description": "The user isn't banned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/wiki-pages": {
      "get": {
        "tags": [
          "wiki"
        ],
        "summary": "List wiki pages.",
        "description": "Most recently changed first, 50 per page. Needs `view_posts`.",
        "operationId": "list_wiki_pages",
        "parameters": [
          {
            "name": "title",
            "in": "query",
            "description": "A title prefix, or a pattern with `*` wildcards.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "1-based.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiPageList"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/wiki-pages/{title}": {
      "get": {
        "tags": [
          "wiki"
        ],
        "summary": "Get a wiki page.",
        "description": "Needs `view_posts`.",
        "operationId": "get_wiki_page",
        "parameters": [
          {
            "name": "title",
            "in": "path",
            "description": "The tag name the page is about",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiWikiPage"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "wiki"
        ],
        "summary": "Create or change a wiki page.",
        "description": "Needs `edit_wiki`. Saving the text the page already has changes\nnothing.",
        "operationId": "save_wiki_page",
        "parameters": [
          {
            "name": "title",
            "in": "path",
            "description": "The tag name the page is about",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WikiChanges"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiWikiPage"
                }
              }
            }
          },
          "409": {
            "description": "The page changed since `base_version`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "422": {
            "description": "The title isn't a valid tag name, or the text is empty or too long",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/wiki-pages/{title}/versions": {
      "get": {
        "tags": [
          "wiki"
        ],
        "summary": "A wiki page's history.",
        "description": "Every version's text, newest first (at most 500). Needs `view_posts`.",
        "operationId": "list_wiki_page_versions",
        "parameters": [
          {
            "name": "title",
            "in": "path",
            "description": "The tag name the page is about",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiWikiVersion"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ApiActiveBan": {
        "type": "object",
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "type": "string"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "`null` for a permanent ban."
          }
        }
      },
      "ApiBan": {
        "type": "object",
        "required": [
          "id",
          "user",
          "reason",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "user": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "banner": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "`null` until lifted."
          }
        }
      },
      "ApiComment": {
        "type": "object",
        "required": [
          "id",
          "post_id",
          "body",
          "html",
          "score",
          "is_deleted",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "post_id": {
            "type": "integer",
            "format": "int64"
          },
          "creator": {
            "type": [
              "string",
              "null"
            ],
            "description": "The author's name, unless their account is gone."
          },
          "body": {
            "type": "string",
            "description": "The text, in the site's wiki markup."
          },
          "html": {
            "type": "string",
            "description": "`body` as HTML, the way the site shows it."
          },
          "score": {
            "type": "integer",
            "format": "int32"
          },
          "is_deleted": {
            "type": "boolean",
            "description": "Only staff see deleted comments."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "edited_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ApiCount": {
        "type": "object",
        "description": "How many posts match. Large counts are estimated.",
        "required": [
          "value",
          "accuracy"
        ],
        "properties": {
          "value": {
            "type": "integer",
            "format": "int64"
          },
          "accuracy": {
            "type": "string",
            "description": "`exact`, `about` (an estimate) or `at_least` (counting stopped)."
          }
        }
      },
      "ApiFavoriteGroup": {
        "type": "object",
        "required": [
          "id",
          "creator",
          "name",
          "is_public",
          "post_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "creator": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Spaces are underscores."
          },
          "is_public": {
            "type": "boolean"
          },
          "post_count": {
            "type": "integer",
            "format": "int64",
            "description": "All its posts, including those you can't see."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiFavoriteGroupWithPosts": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiFavoriteGroup"
          },
          {
            "type": "object",
            "required": [
              "post_ids"
            ],
            "properties": {
              "post_ids": {
                "type": "array",
                "items": {
                  "type": "integer",
                  "format": "int64"
                },
                "description": "The posts you can see, in order."
              }
            }
          }
        ]
      },
      "ApiFile": {
        "type": "object",
        "description": "The original file.",
        "required": [
          "url",
          "media_type",
          "width",
          "height",
          "size",
          "frames",
          "has_audio",
          "sha256",
          "md5",
          "processed"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "On private sites this link expires after an hour or two."
          },
          "media_type": {
            "type": "string",
            "description": "`jpeg`, `png`, `gif`, `webp`, `avif`, `jxl`, `mp4` or `webm`."
          },
          "width": {
            "type": "integer",
            "format": "int32"
          },
          "height": {
            "type": "integer",
            "format": "int32"
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "description": "In bytes."
          },
          "duration_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "frames": {
            "type": "integer",
            "format": "int32",
            "description": "More than 1 for animations."
          },
          "has_audio": {
            "type": "boolean"
          },
          "sha256": {
            "type": "string",
            "description": "Hex."
          },
          "md5": {
            "type": "string",
            "description": "Hex."
          },
          "processed": {
            "type": "boolean",
            "description": "Whether thumbnails and the perceptual hash are done."
          }
        }
      },
      "ApiFlag": {
        "type": "object",
        "required": [
          "reason",
          "created_at"
        ],
        "properties": {
          "creator": {
            "type": [
              "string",
              "null"
            ]
          },
          "reason": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiMe": {
        "type": "object",
        "description": "The account making the request.",
        "required": [
          "name",
          "role",
          "permissions",
          "settings",
          "uploads"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What this account may do now (`upload`, `edit_posts`, …). While\nbanned, only what visitors may."
          },
          "settings": {
            "$ref": "#/components/schemas/ApiSettings"
          },
          "ban": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ApiActiveBan",
                "description": "Set while banned."
              },
              {
                "type": "null"
              }
            ]
          },
          "uploads": {
            "$ref": "#/components/schemas/ApiUploadAllowance"
          }
        }
      },
      "ApiNetworkBan": {
        "type": "object",
        "required": [
          "id",
          "network",
          "reason",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "network": {
            "type": "string",
            "description": "A CIDR range.",
            "example": "203.0.113.0/24"
          },
          "reason": {
            "type": "string"
          },
          "banner": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ApiNote": {
        "type": "object",
        "required": [
          "id",
          "post_id",
          "x",
          "y",
          "width",
          "height",
          "body",
          "html",
          "is_active",
          "version",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "post_id": {
            "type": "integer",
            "format": "int64"
          },
          "x": {
            "type": "integer",
            "format": "int32",
            "description": "The box, in the original image's pixels."
          },
          "y": {
            "type": "integer",
            "format": "int32"
          },
          "width": {
            "type": "integer",
            "format": "int32"
          },
          "height": {
            "type": "integer",
            "format": "int32"
          },
          "body": {
            "type": "string",
            "description": "In the site's wiki markup."
          },
          "html": {
            "type": "string",
            "description": "`body` as HTML."
          },
          "is_active": {
            "type": "boolean",
            "description": "False once deleted."
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "Counts up with every change; send it back when changing the note."
          },
          "updater": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiNoteVersion": {
        "type": "object",
        "required": [
          "note_id",
          "post_id",
          "version",
          "x",
          "y",
          "width",
          "height",
          "body",
          "is_active",
          "created_at"
        ],
        "properties": {
          "note_id": {
            "type": "integer",
            "format": "int64"
          },
          "post_id": {
            "type": "integer",
            "format": "int64"
          },
          "version": {
            "type": "integer",
            "format": "int32"
          },
          "updater": {
            "type": [
              "string",
              "null"
            ]
          },
          "x": {
            "type": "integer",
            "format": "int32"
          },
          "y": {
            "type": "integer",
            "format": "int32"
          },
          "width": {
            "type": "integer",
            "format": "int32"
          },
          "height": {
            "type": "integer",
            "format": "int32"
          },
          "body": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiPool": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "category",
          "is_deleted",
          "version",
          "post_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "Spaces are underscores."
          },
          "description": {
            "type": "string",
            "description": "In the site's wiki markup."
          },
          "category": {
            "type": "string",
            "description": "`series` or `collection`."
          },
          "is_deleted": {
            "type": "boolean"
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "Counts up with every change; send it back when saving."
          },
          "updater": {
            "type": [
              "string",
              "null"
            ]
          },
          "post_count": {
            "type": "integer",
            "format": "int64",
            "description": "All its posts, including those you can't see."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiPoolVersion": {
        "type": "object",
        "required": [
          "version",
          "name",
          "description",
          "category",
          "is_deleted",
          "post_ids",
          "created_at"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "format": "int32"
          },
          "updater": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "is_deleted": {
            "type": "boolean"
          },
          "post_ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiPoolWithPosts": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiPool"
          },
          {
            "type": "object",
            "required": [
              "html",
              "post_ids"
            ],
            "properties": {
              "html": {
                "type": "string",
                "description": "`description` as HTML."
              },
              "post_ids": {
                "type": "array",
                "items": {
                  "type": "integer",
                  "format": "int64"
                },
                "description": "The posts you can see, in order."
              }
            }
          }
        ]
      },
      "ApiPost": {
        "type": "object",
        "description": "A post with its tags and files.",
        "required": [
          "id",
          "rating",
          "status",
          "source",
          "description",
          "score",
          "fav_count",
          "comment_count",
          "note_count",
          "created_at",
          "tags",
          "file",
          "variants"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "rating": {
            "type": "string",
            "description": "`g` (general), `s` (sensitive), `q` (questionable) or `e` (explicit).",
            "example": "s"
          },
          "status": {
            "type": "string",
            "description": "`active`, `pending` (awaiting approval), `flagged` or `deleted`."
          },
          "source": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "parent_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "score": {
            "type": "integer",
            "format": "int32"
          },
          "fav_count": {
            "type": "integer",
            "format": "int32"
          },
          "comment_count": {
            "type": "integer",
            "format": "int32",
            "description": "Comments that aren't deleted."
          },
          "last_commented_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the newest of those was written."
          },
          "note_count": {
            "type": "integer",
            "format": "int32",
            "description": "Notes that aren't deleted."
          },
          "last_noted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When a note was last changed."
          },
          "uploader": {
            "type": [
              "string",
              "null"
            ],
            "description": "The uploader's name, unless their account is gone."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PostTag"
            },
            "description": "Sorted by name."
          },
          "file": {
            "$ref": "#/components/schemas/ApiFile"
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiVariant"
            },
            "description": "Smaller renditions (`thumb-<size>`, `sample`, `poster` for videos),\nonce processing has made them."
          }
        }
      },
      "ApiRelation": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "antecedent",
          "consequent",
          "status",
          "reason",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "kind": {
            "type": "string",
            "description": "`alias` or `implication`."
          },
          "antecedent": {
            "type": "string"
          },
          "consequent": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "`pending`, `active`, `rejected` or `deleted`."
          },
          "reason": {
            "type": "string",
            "description": "Why it was requested."
          },
          "creator": {
            "type": [
              "string",
              "null"
            ]
          },
          "approver": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiSavedSearch": {
        "type": "object",
        "required": [
          "id",
          "query",
          "labels",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "query": {
            "type": "string",
            "description": "Normalised."
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiSettings": {
        "type": "object",
        "required": [
          "theme",
          "blacklist"
        ],
        "properties": {
          "per_page": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Posts per page on the site; `null` for the site's default.",
            "minimum": 0
          },
          "theme": {
            "type": "string",
            "description": "`system`, `light` or `dark`."
          },
          "blacklist": {
            "type": "string",
            "description": "The blacklist in effect: the account's own, or the site's default."
          }
        }
      },
      "ApiTag": {
        "type": "object",
        "required": [
          "id",
          "name",
          "category",
          "post_count",
          "deprecated",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "post_count": {
            "type": "integer",
            "format": "int32"
          },
          "deprecated": {
            "type": "boolean",
            "description": "Deprecated tags can't be added to posts."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiUploadAllowance": {
        "type": "object",
        "description": "How many more posts the account may upload now.",
        "properties": {
          "refused": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why uploading is refused now, if it is."
          },
          "pending_left": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Uploads left before the approval queue's limit; `null` if none\napplies."
          },
          "today_left": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Uploads left today; `null` if there's no daily limit."
          }
        }
      },
      "ApiUser": {
        "type": "object",
        "required": [
          "name",
          "status",
          "created_at",
          "uploads",
          "favorites"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "role": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "description": "`active`, `pending` (awaiting approval) or `deactivated`."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "uploads": {
            "type": "integer",
            "format": "int64"
          },
          "favorites": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ApiVariant": {
        "type": "object",
        "required": [
          "kind",
          "url",
          "format",
          "width",
          "height",
          "size"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "example": "thumb-250"
          },
          "url": {
            "type": "string"
          },
          "format": {
            "type": "string"
          },
          "width": {
            "type": "integer",
            "format": "int32"
          },
          "height": {
            "type": "integer",
            "format": "int32"
          },
          "size": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ApiVersion": {
        "type": "object",
        "description": "One version of a post.",
        "required": [
          "version",
          "tags",
          "added",
          "removed",
          "rating",
          "source",
          "description",
          "created_at"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "1 for the upload, counting up."
          },
          "updater": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who made the change."
          },
          "relation": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/VersionRelation",
                "description": "Set when a tag alias or implication made the change."
              },
              {
                "type": "null"
              }
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "All tags after the change, sorted."
          },
          "added": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "removed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rating": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "parent_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiWikiPage": {
        "type": "object",
        "required": [
          "title",
          "body",
          "html",
          "version",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "The tag name the page is about."
          },
          "body": {
            "type": "string",
            "description": "The page's text, in the site's wiki markup."
          },
          "html": {
            "type": "string",
            "description": "`body` as HTML, the way the site shows it."
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "Counts up with every change; send it back when saving."
          },
          "updater": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who made the latest change."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiWikiSummary": {
        "type": "object",
        "required": [
          "title",
          "version",
          "updated_at"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "version": {
            "type": "integer",
            "format": "int32"
          },
          "updater": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiWikiVersion": {
        "type": "object",
        "required": [
          "version",
          "body",
          "created_at"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "format": "int32"
          },
          "updater": {
            "type": [
              "string",
              "null"
            ]
          },
          "body": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BanList": {
        "type": "object",
        "required": [
          "users",
          "networks"
        ],
        "properties": {
          "users": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiBan"
            },
            "description": "Active user bans, newest first (at most 200)."
          },
          "networks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiNetworkBan"
            },
            "description": "Active network bans."
          }
        }
      },
      "CommentList": {
        "type": "object",
        "required": [
          "comments"
        ],
        "properties": {
          "comments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiComment"
            },
            "description": "Newest first."
          },
          "next_before": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "`before` for the next page; absent on the last one."
          }
        }
      },
      "CommentScore": {
        "type": "object",
        "description": "A comment's score and the viewer's vote.",
        "required": [
          "score",
          "vote"
        ],
        "properties": {
          "score": {
            "type": "integer",
            "format": "int32"
          },
          "vote": {
            "type": "integer",
            "format": "int32",
            "description": "Your vote: 1, -1, or 0 for none."
          }
        }
      },
      "CommentText": {
        "type": "object",
        "required": [
          "body"
        ],
        "properties": {
          "body": {
            "type": "string",
            "description": "In the site's wiki markup; at most 10,000 characters."
          }
        },
        "additionalProperties": false
      },
      "CommentVote": {
        "type": "object",
        "required": [
          "score"
        ],
        "properties": {
          "score": {
            "type": "integer",
            "format": "int32",
            "description": "1, -1, or 0 to take your vote back."
          }
        },
        "additionalProperties": false
      },
      "Dismissed": {
        "type": "object",
        "required": [
          "dismissed"
        ],
        "properties": {
          "dismissed": {
            "type": "integer",
            "format": "int64",
            "description": "How many open flags were dismissed.",
            "minimum": 0
          }
        }
      },
      "ErrorBody": {
        "type": "object",
        "description": "The API's error body.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorDetail"
          }
        }
      },
      "ErrorDetail": {
        "type": "object",
        "required": [
          "status",
          "message"
        ],
        "properties": {
          "status": {
            "type": "integer",
            "format": "int32",
            "description": "The HTTP status code again.",
            "minimum": 0
          },
          "message": {
            "type": "string",
            "description": "What went wrong, for people."
          },
          "post_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "For a duplicate upload, the post that already has the file."
          }
        }
      },
      "FlaggedPost": {
        "type": "object",
        "required": [
          "post_id",
          "flags"
        ],
        "properties": {
          "post_id": {
            "type": "integer",
            "format": "int64"
          },
          "flags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiFlag"
            }
          }
        }
      },
      "GroupInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_public": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Public (the default) or private."
          },
          "post_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "integer",
              "format": "int64"
            },
            "description": "All of its posts, in order."
          }
        },
        "additionalProperties": false
      },
      "GroupPost": {
        "type": "object",
        "required": [
          "post_id"
        ],
        "properties": {
          "post_id": {
            "type": "integer",
            "format": "int64"
          }
        },
        "additionalProperties": false
      },
      "LogEntry": {
        "type": "object",
        "required": [
          "id",
          "action",
          "reason",
          "details",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "actor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who did it; `null` for the command line."
          },
          "action": {
            "type": "string",
            "example": "post.delete"
          },
          "post_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "user": {
            "type": [
              "string",
              "null"
            ],
            "description": "The user acted on."
          },
          "reason": {
            "type": "string"
          },
          "details": {
            "type": "object",
            "description": "Anything else recorded, depending on the action."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LogPage": {
        "type": "object",
        "required": [
          "entries"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LogEntry"
            },
            "description": "Newest first, 50 per page."
          },
          "next_before": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "`before` for the next page; absent on the last one."
          }
        }
      },
      "NewBan": {
        "type": "object",
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "type": "string",
            "description": "Shown to the user while banned."
          },
          "days": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "How long, in days; leave out for until lifted."
          }
        }
      },
      "NewFlag": {
        "type": "object",
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "type": "string",
            "description": "Why the post should be deleted."
          }
        }
      },
      "NewNetworkBan": {
        "type": "object",
        "required": [
          "network",
          "reason"
        ],
        "properties": {
          "network": {
            "type": "string",
            "description": "An address, or a range like `203.0.113.0/24`. It may not include\nyour own address."
          },
          "reason": {
            "type": "string"
          },
          "days": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "How long, in days; leave out for until lifted."
          }
        }
      },
      "NewNote": {
        "type": "object",
        "required": [
          "x",
          "y",
          "width",
          "height",
          "body"
        ],
        "properties": {
          "x": {
            "type": "integer",
            "format": "int32",
            "description": "The box, in the original image's pixels; trimmed to the image."
          },
          "y": {
            "type": "integer",
            "format": "int32"
          },
          "width": {
            "type": "integer",
            "format": "int32"
          },
          "height": {
            "type": "integer",
            "format": "int32"
          },
          "body": {
            "type": "string",
            "description": "In the site's wiki markup; at most 10,000 characters."
          }
        },
        "additionalProperties": false
      },
      "NewPool": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "`series` (the default) or `collection`."
          },
          "post_ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int64"
            },
            "description": "In order."
          }
        },
        "additionalProperties": false
      },
      "NewRelation": {
        "type": "object",
        "required": [
          "kind",
          "antecedent",
          "consequent"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "alias",
              "implication"
            ]
          },
          "antecedent": {
            "type": "string",
            "description": "The tag that's aliased, or that implies the other."
          },
          "consequent": {
            "type": "string",
            "description": "The tag it's aliased to, or that it implies."
          },
          "reason": {
            "type": "string",
            "description": "Why, for whoever reviews the request."
          }
        }
      },
      "NoteChanges": {
        "type": "object",
        "properties": {
          "x": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "A new box: all four or none."
          },
          "y": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "width": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "height": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "body": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_active": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "`false` deletes the note, `true` restores it."
          },
          "base_version": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The version the changes were based on. If someone has changed the\nnote since, the change is refused with 409. Leave it out to change\nwhatever is there."
          }
        },
        "additionalProperties": false
      },
      "PoolChanges": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "post_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "integer",
              "format": "int64"
            },
            "description": "All of the pool's posts, in order."
          },
          "base_version": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The version the changes were based on. If someone has changed the\npool since, the save is refused with 409. Leave it out to save over\nwhatever is there."
          }
        },
        "additionalProperties": false
      },
      "PoolList": {
        "type": "object",
        "required": [
          "pools"
        ],
        "properties": {
          "pools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiPool"
            }
          },
          "next_page": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "`page` for the next page; absent on the last one."
          }
        }
      },
      "PoolPost": {
        "type": "object",
        "required": [
          "post_id"
        ],
        "properties": {
          "post_id": {
            "type": "integer",
            "format": "int64"
          }
        },
        "additionalProperties": false
      },
      "PostChanges": {
        "type": "object",
        "description": "Changes to a post. Fields left out stay as they are.",
        "properties": {
          "rating": {
            "type": [
              "string",
              "null"
            ],
            "description": "`g`, `s`, `q` or `e`."
          },
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "parent_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Another post's number, or `null` for none."
          },
          "tags": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "The complete new list of tags. A category prefix (`artist:name`)\nsets the category of a tag that's new. Can't be combined with\n`add_tags` or `remove_tags`."
          },
          "add_tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags to add, keeping the others."
          },
          "remove_tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags to take off, keeping the others."
          }
        },
        "additionalProperties": false
      },
      "PostPage": {
        "type": "object",
        "description": "A page of search results.",
        "required": [
          "posts",
          "count"
        ],
        "properties": {
          "posts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiPost"
            }
          },
          "count": {
            "$ref": "#/components/schemas/ApiCount"
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "`page` for the next page; absent on the last one."
          },
          "previous": {
            "type": [
              "string",
              "null"
            ],
            "description": "`page` for the previous page; absent on the first one."
          }
        }
      },
      "PostTag": {
        "type": "object",
        "required": [
          "name",
          "category"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "description": "`general`, `artist`, `copyright`, `character`, `meta`, or a\ncategory the site added."
          }
        }
      },
      "Reactions": {
        "type": "object",
        "description": "A post's counts and the viewer's part in them.",
        "required": [
          "fav_count",
          "favorited",
          "score",
          "vote"
        ],
        "properties": {
          "fav_count": {
            "type": "integer",
            "format": "int32"
          },
          "favorited": {
            "type": "boolean",
            "description": "Whether you have favorited the post."
          },
          "score": {
            "type": "integer",
            "format": "int32"
          },
          "vote": {
            "type": "integer",
            "format": "int32",
            "description": "Your vote: 1, -1, or 0 for none."
          }
        }
      },
      "Reason": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Shown on the post and in the moderation log."
          }
        }
      },
      "RelationPage": {
        "type": "object",
        "required": [
          "relations"
        ],
        "properties": {
          "relations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiRelation"
            }
          },
          "next_page": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "`page` for the next page; absent on the last one."
          }
        }
      },
      "SavedSearchInput": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string"
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Letters, digits, `_` and `-`; at most 10."
          }
        },
        "additionalProperties": false
      },
      "Suggestion": {
        "type": "object",
        "description": "A tag suggested for what was typed so far.",
        "required": [
          "name",
          "category",
          "post_count"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "post_count": {
            "type": "integer",
            "format": "int32"
          },
          "antecedent": {
            "type": [
              "string",
              "null"
            ],
            "description": "The alias that matched, when `name` is its target."
          }
        }
      },
      "TagChanges": {
        "type": "object",
        "description": "Changes to a tag. Fields left out stay as they are.",
        "properties": {
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "The category's name (`general`, `artist`, …)."
          },
          "deprecated": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Deprecated tags can't be added to posts."
          }
        },
        "additionalProperties": false
      },
      "TagPage": {
        "type": "object",
        "required": [
          "tags"
        ],
        "properties": {
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiTag"
            }
          },
          "next_page": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "`page` for the next page; absent on the last one."
          }
        }
      },
      "UploadRequest": {
        "type": "object",
        "description": "The fields of an upload, for the description only: the handler reads\nthe multipart body as the upload form does.",
        "required": [
          "rating"
        ],
        "properties": {
          "file": {
            "type": [
              "string",
              "null"
            ],
            "format": "binary",
            "description": "The file. Send either this or `url`."
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "A link to download the file from, instead of sending it. It also\nbecomes the source when none is given."
          },
          "rating": {
            "type": "string",
            "description": "`g`, `s`, `q` or `e`."
          },
          "tags": {
            "type": [
              "string",
              "null"
            ],
            "description": "Whitespace-separated. A category prefix (`artist:name`) sets the\ncategory of a tag that's new."
          },
          "source": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "VersionRelation": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "description": "`alias` or `implication`."
          },
          "antecedent": {
            "type": [
              "string",
              "null"
            ]
          },
          "consequent": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Vote": {
        "type": "object",
        "required": [
          "score"
        ],
        "properties": {
          "score": {
            "type": "integer",
            "format": "int32",
            "description": "1 (up), -1 (down), or 0 to take your vote back."
          }
        }
      },
      "WikiChanges": {
        "type": "object",
        "required": [
          "body"
        ],
        "properties": {
          "body": {
            "type": "string",
            "description": "The new text, in the site's wiki markup."
          },
          "base_version": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The version the text was based on, 0 for a new page. If someone\nhas changed the page since, the save is refused with 409. Leave it\nout to save over whatever is there."
          }
        },
        "additionalProperties": false
      },
      "WikiPageList": {
        "type": "object",
        "required": [
          "pages"
        ],
        "properties": {
          "pages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiWikiSummary"
            }
          },
          "next_page": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "`page` for the next page; absent on the last one."
          }
        }
      }
    },
    "securitySchemes": {
      "api_key": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from your account settings."
      },
      "session": {
        "type": "apiKey",
        "in": "cookie",
        "name": "moekura_session",
        "description": "The site's login session, for scripts running on its pages."
      }
    }
  },
  "security": [
    {},
    {
      "api_key": []
    },
    {
      "session": []
    }
  ],
  "tags": [
    {
      "name": "posts",
      "description": "Searching, viewing and changing posts."
    },
    {
      "name": "tags",
      "description": "Tags, their categories, aliases and implications."
    },
    {
      "name": "users",
      "description": "Users and the account making the request."
    },
    {
      "name": "wiki",
      "description": "Wiki pages about tags, and their history."
    },
    {
      "name": "comments",
      "description": "Comments on posts, their votes and reports."
    },
    {
      "name": "pools",
      "description": "Ordered collections of posts, and their history."
    },
    {
      "name": "notes",
      "description": "Notes (translations) on posts' images, and their history."
    },
    {
      "name": "moderation",
      "description": "Reviewing posts and flags, deciding tag relations, bans and the moderation log."
    }
  ]
}