{
  "openapi": "3.1.0",
  "info": {
    "title": "zpe files",
    "version": "5.0.0",
    "description": "A file store on zpe.vc/files: one prefix of the bucket per account, with the same files in the browser, over the mount, and here. Every operation lives under the versioned base `/_/api/v1`, and this document is served at `/_/api/v1/openapi.json`. Authenticate with the account's session cookie or with a token minted on the app's own page."
  },
  "servers": [
    {
      "url": "/files",
      "description": "zpe-files on zpe.vc"
    }
  ],
  "paths": {
    "/_/api/v1/copy": {
      "post": {
        "operationId": "postCopy",
        "summary": "Copy a file or a whole folder to another path",
        "tags": [
          "copy"
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "description": "The file or folder to copy. Send it here or as `from` in a JSON body.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Where the copy goes. Send it here or as `to` in a JSON body.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overwrite",
            "in": "query",
            "description": "Replace the destination when it already exists. Default false.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file was copied. `from` still exists: a copy does not move it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`from` or `to` is missing, is not a usable key, names the internal prefix, is the same as the other, or sits inside it; or the JSON body could not be read.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`from` names nothing in this account's prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`to` is already there and `overwrite` was not asked for.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/counts": {
      "post": {
        "operationId": "postCounts",
        "summary": "Count the direct children of one or more folders",
        "tags": [
          "counts"
        ],
        "responses": {
          "200": {
            "description": "One count per folder, keyed by path. A folder that could not be counted is absent rather than zero, so a missing key means `unknown`, not `empty`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The JSON body could not be read, so there were no folders to count.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/delete": {
      "delete": {
        "operationId": "deleteDelete",
        "summary": "Delete a file or folder, or move it to the trash with `?soft=1`",
        "tags": [
          "delete"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The file or folder to delete, relative to the account's prefix.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "soft",
            "in": "query",
            "description": "Move it to the trash instead of deleting it.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "It is gone, or — with `soft` — it moved to the trash and this is the `trashKey` a restore takes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`path` is missing or is not a usable key, or names the internal prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`path` names nothing in this account's prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/download": {
      "get": {
        "operationId": "getDownload",
        "summary": "Download one file's bytes",
        "tags": [
          "download"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The object key to read, relative to the account's prefix.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file's bytes, with its type, length and `ETag`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "206": {
            "description": "Part of the file's bytes, when the request carried a `Range` header.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`path` is missing or is not a usable key, or names a folder: a folder has no bytes to send.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`path` names nothing in this account's prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/list": {
      "get": {
        "operationId": "getList",
        "summary": "List one folder, sorted, folders first",
        "tags": [
          "list"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The folder to list, relative to the account's prefix. The root when absent.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "How many entries to answer. The whole folder when absent.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "The `nextCursor` a previous page answered, to read the next one.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The folder's entries, folders first, and a `nextCursor` when there is another page.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`path` is not a usable key, names a file rather than a folder, or `limit` is outside 1-1000.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`path` names no folder in this account's prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/mkdir": {
      "post": {
        "operationId": "postMkdir",
        "summary": "Create a folder, with its parent markers",
        "tags": [
          "mkdir"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The folder to create, relative to the account's prefix.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "A value that names this attempt. Send the same one when retrying and the answer is what the first call wrote (`200`) instead of a second object; present and empty is refused.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Nothing new was written: this `Idempotency-Key` already created that folder, or the folder was already there. `created` is `false` and `existed` says what was found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "key",
                    "created"
                  ],
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "created": {
                      "type": "boolean"
                    },
                    "existed": {
                      "type": "string",
                      "enum": [
                        "directory",
                        "prefix"
                      ]
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "The folder was created, with its parent markers.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "key",
                    "created"
                  ],
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "created": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is here",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "A file of that name is already there, so a folder cannot take the address.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/rename": {
      "post": {
        "operationId": "postRename",
        "summary": "Rename or move a file or folder",
        "tags": [
          "rename"
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "description": "The file or folder to move. Send it here or as `from` in a JSON body.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Its new path. Send it here or as `to` in a JSON body.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overwrite",
            "in": "query",
            "description": "Replace the destination when it already exists. Default false.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "It moved, and `from` no longer exists.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`from` or `to` is missing or is not a usable key, is the same as the other or sits inside it, names the internal prefix, or `overwrite` was asked for on a folder move; or the JSON body could not be read.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`from` names nothing in this account's prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "`to` is already there, and either `overwrite` was not asked for or the destination is a folder.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/search": {
      "get": {
        "operationId": "getSearch",
        "summary": "Search the account's files by name",
        "tags": [
          "search"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "The text to find in a file's name. An empty one answers nothing rather than everything.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "How many hits to answer. Default 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "prefix",
            "in": "query",
            "description": "Only search under this folder, relative to the account's prefix.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "match",
            "in": "query",
            "description": "`name` matches a file's whole name instead of a substring of it, for a caller that knows the name it wants.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "name"
              ]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "The `nextCursor` a previous page answered, to read the next one.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The names that matched, and a `nextCursor` when the scan stopped with more to read. An empty `q` answers an empty page rather than every file.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/stat": {
      "get": {
        "operationId": "getStat",
        "summary": "Read one file's metadata without its bytes",
        "tags": [
          "stat"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The object key to read the metadata of, relative to the account's prefix.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One file's or folder's metadata, without its bytes. A folder answers `kind: directory`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`path` is missing or is not a usable key, or names the internal prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "`path` names nothing in this account's prefix.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/trash": {
      "delete": {
        "operationId": "deleteTrash",
        "summary": "List the trash, restore from it, or empty it",
        "tags": [
          "trash"
        ],
        "responses": {
          "204": {
            "description": "The named `trashKeys` — or everything, with `all` — were removed from the trash and their bytes with them. Nothing to send back."
          },
          "400": {
            "description": "The JSON body could not be read, so there were no entries to remove.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "operationId": "getTrash",
        "summary": "List the trash, restore from it, or empty it",
        "tags": [
          "trash"
        ],
        "responses": {
          "200": {
            "description": "Everything in the trash, including entries whose retention has just run out and been purged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "postTrash",
        "summary": "List the trash, restore from it, or empty it",
        "tags": [
          "trash"
        ],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "description": "`restore` restores the keys named in the body. Absent, the body's keys are soft-deleted instead.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "restore"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "`action=restore` answers one result per `trashKey` — restored, or why it could not be. Without it, the body's `keys` moved to the trash and this is each one's id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The JSON body could not be read, or — without `action=restore` — carried no `keys` to move.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/upload": {
      "delete": {
        "operationId": "deleteUpload",
        "summary": "Upload a file, or write and remove one raw PUT at a time",
        "tags": [
          "upload"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The file key the abandoned upload was for.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "uploadId",
            "in": "query",
            "description": "The multipart upload to abandon.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The multipart upload was abandoned and its parts are gone. An `uploadId` that was never live is treated as already abandoned, so this answer is idempotent."
          },
          "400": {
            "description": "`path` or `uploadId` is missing or is not a usable key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "operationId": "postUpload",
        "summary": "Upload a file, or write and remove one raw PUT at a time",
        "tags": [
          "upload"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The folder to write into — or, with `uploads`, the file key the multipart upload is for.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "uploads",
            "in": "query",
            "description": "Start a multipart upload and answer its `uploadId`. Send it with no value.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "uploadId",
            "in": "query",
            "description": "Complete the multipart upload this id names, with the parts in a JSON body.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overwrite",
            "in": "query",
            "description": "Replace a file of the same name. Default false.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "A value that names this attempt. Send the same one when retrying and the answer is what the first call wrote (`200`) instead of a second object; present and empty is refused.",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Nothing new was written: this `Idempotency-Key` already answered here, and this is what the first call wrote — the same key, name, size and `uploadId`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "size": {
                      "type": "integer"
                    },
                    "path": {
                      "type": "string"
                    },
                    "overwritten": {
                      "type": "boolean"
                    },
                    "uploadId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "The file was written, or — with `uploads` — a multipart upload was started and this is its `uploadId`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "size": {
                      "type": "integer"
                    },
                    "path": {
                      "type": "string"
                    },
                    "overwritten": {
                      "type": "boolean"
                    },
                    "uploadId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is here",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The destination is a folder, so it cannot be replaced by this file.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than this deployment accepts in one request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "put": {
        "operationId": "putUpload",
        "summary": "Upload a file, or write and remove one raw PUT at a time",
        "tags": [
          "upload"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "description": "The file key this part belongs to.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "uploadId",
            "in": "query",
            "description": "The multipart upload this part belongs to.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "partNumber",
            "in": "query",
            "description": "Which part this body is, counted from 1.",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The part was written, and this is its `partNumber` and `ETag` for the completing call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`path`, `uploadId` or `partNumber` is missing or is not usable, the request carried no body, or the upload refused the part.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that: the key's scope does not cover this method, or the door's grant does not name this app",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, and `Retry-After` says when to come back",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer — the door could not be reached, so this request was not checked",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key minted on the account's settings page at zpe.vc/home/settings. Send it as `Authorization: Bearer <key>`."
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem+json: `type`, `title`, `status`, `code` and `instance`, plus `detail` when a person should read a sentence.",
        "required": [
          "type",
          "title",
          "status",
          "code",
          "instance"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "enum": [
              "bad-request",
              "unauthenticated",
              "malformed",
              "unknown",
              "mismatch",
              "revoked",
              "expired",
              "another-account",
              "scope-refused",
              "grant-refused",
              "forbidden",
              "not-found",
              "method-not-allowed",
              "conflict",
              "gone",
              "payload-too-large",
              "unsupported-media-type",
              "unprocessable",
              "rate-limited",
              "payment-required",
              "not-open",
              "internal",
              "unavailable"
            ]
          },
          "instance": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        }
      }
    }
  },
  "x-surface": {
    "app": "zpe-files",
    "base": "/_/api/v1",
    "document": "/_/api/v1/openapi.json",
    "generated_by": "zpe-kit machineDocument"
  },
  "x-zpe-routes": 15,
  "x-zpe-documented": 15,
  "x-zpe-internal": []
}
