openapi: 3.0.3
tags:
  - name: healthcheck
  - name: token
  - name: maintenance
  - name: admins
  - name: connections
  - name: defender
  - name: quota
  - name: folders
  - name: users
info:
  title: SFTPGo
  description: SFTPGo REST API
  version: 2.0.5
  contact:
    name: API support
    url: 'https://github.com/drakkan/sftpgo'
  license:
    name: AGPLv3
    url: 'https://www.gnu.org/licenses/agpl-3.0.en.html'
servers:
  - url: /api/v2
security:
  - BearerAuth: []
paths:
  /healthz:
    get:
      security: []
      servers:
        - url: /
      tags:
        - healthcheck
      summary: health check
      description: This endpoint can be used to check if the application is running and responding to requests
      operationId: healthz
      responses:
        '200':
          description: successful operation
          content:
            text/plain:
              schema:
                type: string
                example: ok
  /token:
    get:
      security:
        - BasicAuth: []
      tags:
        - token
      summary: Get a new access token
      description: Returns an access token and its expiration
      operationId: get_token
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Token'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /logout:
    get:
      tags:
        - token
      summary: Invalidate
      description: Allows to invalidate a token before its expiration
      operationId: logout
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /version:
    get:
      tags:
        - maintenance
      summary: Get version details
      description: 'Returns version details such as the version number, build date, commit hash and enabled features'
      operationId: get_version
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VersionInfo'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /changepwd/admin:
    put:
      tags:
        - admins
      summary: Change admin password
      description: Changes the password for the logged in admin
      operationId: change_admin_password
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PwdChange'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /connections:
    get:
      tags:
        - connections
      summary: Get connections details
      description: Returns the active users and info about their current uploads/downloads
      operationId: get_connections
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ConnectionStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  '/connections/{connectionID}':
    delete:
      tags:
        - connections
      summary: Close connection
      description: Terminates an active connection
      operationId: close_connection
      parameters:
        - name: connectionID
          in: path
          description: ID of the connection to close
          required: true
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Connection closed
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /defender/bantime:
    get:
      tags:
        - defender
      summary: Get ban time
      description: Returns the ban time for the specified IPv4/IPv6 address
      operationId: get_ban_time
      parameters:
        - in: query
          name: ip
          required: true
          description: IPv4/IPv6 address
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BanStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /defender/unban:
    post:
      tags:
        - defender
      summary: Unban
      description: Removes the specified IPv4/IPv6 from the banned ones
      operationId: unban_host
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ip:
                  type: string
                  description: IPv4/IPv6 address to remove
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /defender/score:
    get:
      tags:
        - defender
      summary: Get score
      description: Returns the score for the specified IPv4/IPv6 address
      operationId: get_score
      parameters:
        - in: query
          name: ip
          required: true
          description: IPv4/IPv6 address
          schema:
            type: string
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScoreStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /quota-scans:
    get:
      tags:
        - quota
      summary: Get quota scans
      description: Returns active user quota scans
      operationId: get_quota_scans
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/QuotaScan'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    post:
      tags:
        - quota
      summary: Start user quota scan
      description: Starts a new quota scan for the given user. A quota scan updates the number of files and their total size for the specified user and the virtual folders, if any, included in his quota
      operationId: start_quota_scan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '202':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Scan started
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /quota-update:
    put:
      tags:
        - quota
      summary: Update user quota limits
      description: Sets the current used quota limits for the given user
      operationId: quota_update
      parameters:
        - in: query
          name: mode
          required: false
          description: the update mode specifies if the given quota usage values should be added or replace the current ones
          schema:
            type: string
            enum:
              - add
              - reset
            description: |
              Update type:
                * `add` - add the specified quota limits to the current used ones
                * `reset` - reset the values to the specified ones. This is the default
            example: reset
      requestBody:
        required: true
        description: 'The only user mandatory fields are username, used_quota_size and used_quota_files. Please note that if the quota fields are missing they will default to 0, this means that if mode is "add" the current value will remain unchanged, if mode is "reset" the missing field is set to 0'
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Quota updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /folder-quota-update:
    put:
      tags:
        - quota
      summary: Update folder quota limits
      description: Sets the current used quota limits for the given folder
      operationId: folder_quota_update
      parameters:
        - in: query
          name: mode
          required: false
          description: the update mode specifies if the given quota usage values should be added or replace the current ones
          schema:
            type: string
            enum:
              - add
              - reset
            description: |
              Update type:
                * `add` - add the specified quota limits to the current used ones
                * `reset` - reset the values to the specified ones. This is the default
            example: reset
      requestBody:
        required: true
        description: 'The only folder mandatory fields are mapped_path,used_quota_size and used_quota_files. Please note that if the used quota fields are missing they will default to 0, this means that if mode is "add" the current value will remain unchanged, if mode is "reset" the missing field is set to 0'
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaseVirtualFolder'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Quota updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /folder-quota-scans:
    get:
      tags:
        - quota
      summary: Get folders quota scans
      description: Returns the active quota scans for folders
      operationId: get_folders_quota_scans
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FolderQuotaScan'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    post:
      tags:
        - quota
      summary: Start folder quota scan
      description: Starts a new quota scan for the given folder. A quota scan update the number of files and their total size for the specified folder
      operationId: start_folder_quota_scan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaseVirtualFolder'
      responses:
        '202':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Scan started
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /folders:
    get:
      tags:
        - folders
      summary: Get folders
      description: Returns an array with one or more folders
      operationId: get_folders
      parameters:
        - in: query
          name: offset
          schema:
            type: integer
            minimum: 0
            default: 0
          required: false
        - in: query
          name: limit
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
          required: false
          description: 'The maximum number of items to return. Max value is 500, default is 100'
        - in: query
          name: order
          required: false
          description: Ordering folders by path. Default ASC
          schema:
            type: string
            enum:
              - ASC
              - DESC
            example: ASC
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/BaseVirtualFolder'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    post:
      tags:
        - folders
      summary: Add folder
      operationId: add_folder
      description: Adds a new folder. A quota scan is required to update the used files/size
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaseVirtualFolder'
      responses:
        '201':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseVirtualFolder'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  '/folders/{name}':
    parameters:
      - name: name
        in: path
        description: folder name
        required: true
        schema:
          type: string
    get:
      tags:
        - folders
      summary: Find folders by name
      description: Returns the folder with the given name if it exists.
      operationId: get_folder_by_name
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaseVirtualFolder'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    put:
      tags:
        - folders
      summary: Update folder
      description: Updates an existing folder
      operationId: update_folder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaseVirtualFolder'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: User updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    delete:
      tags:
        - folders
      summary: Delete folder
      description: Deletes an existing folder
      operationId: delete_folder
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: User deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /admins:
    get:
      tags:
        - admins
      summary: Get admins
      description: Returns an array with one or more admins. For security reasons hashed passwords are omitted in the response
      operationId: get_admins
      parameters:
        - in: query
          name: offset
          schema:
            type: integer
            minimum: 0
            default: 0
          required: false
        - in: query
          name: limit
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
          required: false
          description: 'The maximum number of items to return. Max value is 500, default is 100'
        - in: query
          name: order
          required: false
          description: Ordering admins by username. Default ASC
          schema:
            type: string
            enum:
              - ASC
              - DESC
            example: ASC
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Admin'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    post:
      tags:
        - admins
      summary: Add admin
      description: Adds a new admin
      operationId: add_admin
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Admin'
            examples:
              example-1:
                value:
                  id: 1
                  status: 0
                  username: string
                  description: string
                  password: pa$$word
                  email: user@example.com
                  permissions:
                    - '*'
                  filters:
                    allow_list:
                      - 192.0.2.0/24
                      - '2001:db8::/32'
                  additional_info: string
      responses:
        '201':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Admin'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  '/admins/{username}':
    parameters:
      - name: username
        in: path
        description: the admin username
        required: true
        schema:
          type: string
    get:
      tags:
        - admins
      summary: Find admins by username
      description: Returns the admin with the given username, if it exists. For security reasons the hashed password is omitted in the response
      operationId: get_admin_by_username
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Admin'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    put:
      tags:
        - admins
      summary: Update admin
      description: Updates an existing admin
      operationId: update_admin
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Admin'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Admin updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    delete:
      tags:
        - admins
      summary: Delete admin
      description: Deletes an existing admin
      operationId: delete_admin
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Admin deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /users:
    get:
      tags:
        - users
      summary: Get users
      description: Returns an array with one or more users. For security reasons hashed passwords are omitted in the response
      operationId: get_users
      parameters:
        - in: query
          name: offset
          schema:
            type: integer
            minimum: 0
            default: 0
          required: false
        - in: query
          name: limit
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
          required: false
          description: 'The maximum number of items to return. Max value is 500, default is 100'
        - in: query
          name: order
          required: false
          description: Ordering users by username. Default ASC
          schema:
            type: string
            enum:
              - ASC
              - DESC
            example: ASC
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    post:
      tags:
        - users
      summary: Add user
      description: Adds a new user
      operationId: add_user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '201':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  '/users/{username}':
    parameters:
      - name: username
        in: path
        description: the username
        required: true
        schema:
          type: string
    get:
      tags:
        - users
      summary: Find users by username
      description: Returns the user with the given username if it exists. For security reasons the hashed password is omitted in the response
      operationId: get_user_by_username
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    put:
      tags:
        - users
      summary: Update user
      description: 'Updates an existing user and optionally disconnects it, if connected, to apply the new settings'
      operationId: update_user
      parameters:
        - in: query
          name: disconnect
          schema:
            type: integer
            enum:
              - 0
              - 1
          description: |
            Disconnect:
              * `0` The user will not be disconnected and it will continue to use the old configuration until connected. This is the default
              * `1` The user will be disconnected after a successful update. It must login again and so it will be forced to use the new configuration
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: User updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    delete:
      tags:
        - users
      summary: Delete user
      description: Deletes an existing user
      operationId: delete_user
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: User deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /status:
    get:
      tags:
        - maintenance
      summary: Get status
      description: Retrieves the status of the active services
      operationId: get_status
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServicesStatus'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /dumpdata:
    get:
      tags:
        - maintenance
      summary: Dump data
      description: 'Backups data as data provider independent JSON. The backup can be saved in a local file on the server, to avoid exposing sensitive data over the network, or returned as response body. The output of dumpdata can be used as input for loaddata'
      operationId: dumpdata
      parameters:
        - in: query
          name: output-file
          schema:
            type: string
          description: Path for the file to write the JSON serialized data to. This path is relative to the configured "backups_path". If this file already exists it will be overwritten. To return the backup as response body set `output_data` to true instead.
        - in: query
          name: output-data
          schema:
            type: integer
            enum:
              - 0
              - 1
          description: |
            output data:
              * `0` or any other value != 1, the backup will be saved to a file on the server, `output_file` is required
              * `1` the backup will be returned as response body
        - in: query
          name: indent
          schema:
            type: integer
            enum:
              - 0
              - 1
          description: |
            indent:
              * `0` no indentation. This is the default
              * `1` format the output JSON
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - $ref: '#/components/schemas/BackupData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
  /loaddata:
    parameters:
      - in: query
        name: scan-quota
        schema:
          type: integer
          enum:
            - 0
            - 1
            - 2
        description: |
          Quota scan:
            * `0` no quota scan is done, the imported users/folders will have used_quota_size and used_quota_files = 0 or the existing values if they already exists. This is the default
            * `1` scan quota
            * `2` scan quota if the user has quota restrictions
          required: false
      - in: query
        name: mode
        schema:
          type: integer
          enum:
            - 0
            - 1
            - 2
        description: |
          Mode:
            * `0` New users/admins are added, existing users/admins are updated. This is the default
            * `1` New users/admins are added, existing users/admins are not modified
            * `2` New users are added, existing users are updated and, if connected, they are disconnected and so forced to use the new configuration
    get:
      tags:
        - maintenance
      summary: Load data from path
      description: 'Restores SFTPGo data from a JSON backup file on the server. Users, folders and admins will be restored one by one and the restore is stopped if a user/folder/admin cannot be added or updated, so it could happen a partial restore'
      operationId: loaddata_from_file
      parameters:
        - in: query
          name: input-file
          schema:
            type: string
          required: true
          description: Path for the file to read the JSON serialized data from. This can be an absolute path or a path relative to the configured "backups_path". The max allowed file size is 10MB
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Data restored
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
    post:
      tags:
        - maintenance
      summary: Load data
      description: 'Restores SFTPGo data from a JSON backup. Users, folders and admins will be restored one by one and the restore is stopped if a user/folder/admin cannot be added or updated, so it could happen a partial restore'
      operationId: loaddata_from_request_body
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BackupData'
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              example:
                message: Data restored
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          $ref: '#/components/responses/DefaultResponse'
components:
  responses:
    BadRequest:
      description: Bad Request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
    Forbidden:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
    NotFound:
      description: Not Found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
    Conflict:
      description: Conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
    InternalServerError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
    DefaultResponse:
      description: Unexpected Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
  schemas:
    Permission:
      type: string
      enum:
        - '*'
        - list
        - download
        - upload
        - overwrite
        - delete
        - rename
        - create_dirs
        - create_symlinks
        - chmod
        - chown
        - chtimes
      description: |
        Permissions:
          * `*` - all permissions are granted
          * `list` - list items is allowed
          * `download` - download files is allowed
          * `upload` - upload files is allowed
          * `overwrite` - overwrite an existing file, while uploading, is allowed. upload permission is required to allow file overwrite
          * `delete` - delete files or directories is allowed
          * `rename` - rename files or directories is allowed
          * `create_dirs` - create directories is allowed
          * `create_symlinks` - create links is allowed
          * `chmod` changing file or directory permissions is allowed
          * `chown` changing file or directory owner and group is allowed
          * `chtimes` changing file or directory access and modification time is allowed
    DirPermissions:
      type: object
      additionalProperties:
        type: array
        items:
          $ref: '#/components/schemas/Permission'
        minItems: 1
      minProperties: 1
      description: 'hash map with directory as key and an array of permissions as value. Directories must be absolute paths, permissions for root directory ("/") are required'
    AdminPermissions:
      type: string
      enum:
        - '*'
        - add_users
        - edit_users
        - del_users
        - view_users
        - view_conns
        - close_conns
        - view_status
        - manage_admins
        - quota_scans
        - manage_system
        - manage_defender
        - view_defender
      description: |
        Admin permissions:
          * `*` - all permissions are granted
          * `add_users` - add new users is allowed
          * `edit_users` - change existing users is allowed
          * `del_users` - remove users is allowed
          * `view_users` - list users is allowed
          * `view_conns` - list active connections is allowed
          * `close_conns` - close active connections is allowed
          * `view_status` - view the server status is allowed
          * `manage_admins` - manage other admins is allowed
          * `manage_defender` - remove ip from the dynamic blocklist is allowed
          * `view_defender` - list the dynamic blocklist is allowed
    LoginMethods:
      type: string
      enum:
        - publickey
        - password
        - keyboard-interactive
        - publickey+password
        - publickey+keyboard-interactive
        - TLSCertificate
        - TLSCertificate+password
      description: |
        Available login methods. To enable multi-step authentication you have to allow only multi-step login methods
          * `publickey`
          * `password`
          * `keyboard-interactive`
          * `publickey+password` - multi-step auth: public key and password
          * `publickey+keyboard-interactive` - multi-step auth: public key and keyboard interactive
          * `TLSCertificate`
          * `TLSCertificate+password` - multi-step auth: TLS client certificate and password
    SupportedProtocols:
      type: string
      enum:
        - SSH
        - FTP
        - DAV
        - HTTP
      description: |
        Protocols:
          * `SSH` - includes both SFTP and SSH commands
          * `FTP` - plain FTP and FTPES/FTPS
          * `DAV` - WebDAV over HTTP/HTTPS
          * `HTTP` - WebClient
    WebClientOptions:
      type: string
      enum:
        - publickey-change-disabled
      description: |
        Options:
          * `publickey-change-disabled` - changing SSH public keys is not allowed
    PatternsFilter:
      type: object
      properties:
        path:
          type: string
          description: 'exposed virtual path, if no other specific filter is defined, the filter apply for sub directories too. For example if filters are defined for the paths "/" and "/sub" then the filters for "/" are applied for any file outside the "/sub" directory'
        allowed_patterns:
          type: array
          items:
            type: string
          description: 'list of, case insensitive, allowed shell like file patterns.'
          example:
            - '*.jpg'
            - a*b?.png
        denied_patterns:
          type: array
          items:
            type: string
          description: 'list of, case insensitive, denied shell like file patterns. Denied patterns are evaluated before the allowed ones'
          example:
            - '*.zip'
    ExtensionsFilter:
      type: object
      properties:
        path:
          type: string
          description: 'exposed virtual path, if no other specific filter is defined, the filter apply for sub directories too. For example if filters are defined for the paths "/" and "/sub" then the filters for "/" are applied for any file outside the "/sub" directory'
        allowed_extensions:
          type: array
          items:
            type: string
          description: 'list of, case insensitive, allowed files extension. Shell like expansion is not supported so you have to specify `.jpg` and not `*.jpg`'
          example:
            - .jpg
            - .png
        denied_extensions:
          type: array
          items:
            type: string
          description: 'list of, case insensitive, denied files extension. Denied file extensions are evaluated before the allowed ones'
          example:
            - .zip
    HooksFilter:
      type: object
      properties:
        external_auth_disabled:
          type: boolean
          example: false
          description: If true, the external auth hook, if defined, will not be executed
        pre_login_disabled:
          type: boolean
          example: false
          description: If true, the pre-login hook, if defined, will not be executed
        check_password_disabled:
          type: boolean
          example: false
          description: If true, the check password hook, if defined, will not be executed
      description: User specific hook overrides
    UserFilters:
      type: object
      properties:
        allowed_ip:
          type: array
          items:
            type: string
          description: 'only clients connecting from these IP/Mask are allowed. IP/Mask must be in CIDR notation as defined in RFC 4632 and RFC 4291, for example "192.0.2.0/24" or "2001:db8::/32"'
          example:
            - 192.0.2.0/24
            - '2001:db8::/32'
        denied_ip:
          type: array
          items:
            type: string
          description: clients connecting from these IP/Mask are not allowed. Denied rules are evaluated before allowed ones
          example:
            - 172.16.0.0/16
        denied_login_methods:
          type: array
          items:
            $ref: '#/components/schemas/LoginMethods'
          description: if null or empty any available login method is allowed
        denied_protocols:
          type: array
          items:
            $ref: '#/components/schemas/SupportedProtocols'
          description: if null or empty any available protocol is allowed
        file_patterns:
          type: array
          items:
            $ref: '#/components/schemas/PatternsFilter'
          description: 'filters based on shell like file patterns. These restrictions do not apply to files listing for performance reasons, so a denied file cannot be downloaded/overwritten/renamed but it will still be in the list of files. Please note that these restrictions can be easily bypassed'
        file_extensions:
          type: array
          items:
            $ref: '#/components/schemas/ExtensionsFilter'
          description: 'filters based on shell like patterns. Deprecated, use file_patterns. These restrictions do not apply to files listing for performance reasons, so a denied file cannot be downloaded/overwritten/renamed but it will still be in the list of files. Please note that these restrictions can be easily bypassed'
        max_upload_file_size:
          type: integer
          format: int64
          description: 'maximum allowed size, as bytes, for a single file upload. The upload will be aborted if/when the size of the file being sent exceeds this limit. 0 means unlimited. This restriction does not apply for SSH system commands such as `git` and `rsync`'
        tls_username:
          type: string
          enum:
            - None
            - CommonName
          description: 'defines the TLS certificate field to use as username. For FTP clients it must match the name provided using the "USER" command. For WebDAV, if no username is provided, the CN will be used as username. For WebDAV clients it must match the implicit or provided username. Ignored if mutual TLS is disabled'
        hooks:
          $ref: '#/components/schemas/HooksFilter'
        disable_fs_checks:
          type: boolean
          example: false
          description: Disable checks for existence and automatic creation of home directory and virtual folders. SFTPGo requires that the user's home directory, virtual folder root, and intermediate paths to virtual folders exist to work properly. If you already know that the required directories exist, disabling these checks will speed up login. You could, for example, disable these checks after the first login
        web_client:
          type: array
          items:
            $ref: '#/components/schemas/WebClientOptions'
          description: WebClient related configuration options
      description: Additional user options
    Secret:
      type: object
      properties:
        status:
          type: string
          enum:
            - Plain
            - AES-256-GCM
            - Secretbox
            - GCP
            - AWS
            - VaultTransit
            - Redacted
          description: 'Set to "Plain" to add or update an existing secret, set to "Redacted" to preserve the existing value'
        payload:
          type: string
        key:
          type: string
        additional_data:
          type: string
        mode:
          type: integer
          description: 1 means encrypted using a master key
      description: The secret is encrypted before saving, so to set a new secret you must provide a payload and set the status to "Plain". The encryption key and additional data will be generated automatically. If you set the status to "Redacted" the existig secret will be preserved
    S3Config:
      type: object
      properties:
        bucket:
          type: string
          minLength: 1
        region:
          type: string
          minLength: 1
        access_key:
          type: string
        access_secret:
          $ref: '#/components/schemas/Secret'
        endpoint:
          type: string
          description: optional endpoint
        storage_class:
          type: string
        upload_part_size:
          type: integer
          description: 'the buffer size (in MB) to use for multipart uploads. The minimum allowed part size is 5MB, and if this value is set to zero, the default value (5MB) for the AWS SDK will be used. The minimum allowed value is 5.'
        upload_concurrency:
          type: integer
          description: 'the number of parts to upload in parallel. If this value is set to zero, the default value (2) will be used'
        key_prefix:
          type: string
          description: 'key_prefix is similar to a chroot directory for a local filesystem. If specified the user will only see contents that starts with this prefix and so you can restrict access to a specific virtual folder. The prefix, if not empty, must not start with "/" and must end with "/". If empty the whole bucket contents will be available'
          example: folder/subfolder/
      description: S3 Compatible Object Storage configuration details
    GCSConfig:
      type: object
      properties:
        bucket:
          type: string
          minLength: 1
        credentials:
          $ref: '#/components/schemas/Secret'
        automatic_credentials:
          type: integer
          enum:
            - 0
            - 1
          description: |
            Automatic credentials:
              * `0` - disabled, explicit credentials, using a JSON credentials file, must be provided. This is the default value if the field is null
              * `1` - enabled, we try to use the Application Default Credentials (ADC) strategy to find your application's credentials
        storage_class:
          type: string
        key_prefix:
          type: string
          description: 'key_prefix is similar to a chroot directory for a local filesystem. If specified the user will only see contents that starts with this prefix and so you can restrict access to a specific virtual folder. The prefix, if not empty, must not start with "/" and must end with "/". If empty the whole bucket contents will be available'
          example: folder/subfolder/
      description: 'Google Cloud Storage configuration details. The "credentials" field must be populated only when adding/updating a user. It will be always omitted, since there are sensitive data, when you search/get users'
    AzureBlobFsConfig:
      type: object
      properties:
        container:
          type: string
        account_name:
          type: string
          description: 'Storage Account Name, leave blank to use SAS URL'
        account_key:
          $ref: '#/components/schemas/Secret'
        sas_url:
          type: string
          description: 'Shared access signature URL, leave blank if using account/key'
        endpoint:
          type: string
          description: 'optional endpoint. Default is "blob.core.windows.net". If you use the emulator the endpoint must include the protocol, for example "http://127.0.0.1:10000"'
        upload_part_size:
          type: integer
          description: 'the buffer size (in MB) to use for multipart uploads. If this value is set to zero, the default value (4MB) will be used.'
        upload_concurrency:
          type: integer
          description: 'the number of parts to upload in parallel. If this value is set to zero, the default value (2) will be used'
        access_tier:
          type: string
          enum:
            - ''
            - Archive
            - Hot
            - Cool
        key_prefix:
          type: string
          description: 'key_prefix is similar to a chroot directory for a local filesystem. If specified the user will only see contents that starts with this prefix and so you can restrict access to a specific virtual folder. The prefix, if not empty, must not start with "/" and must end with "/". If empty the whole container contents will be available'
          example: folder/subfolder/
        use_emulator:
          type: boolean
      description: Azure Blob Storage configuration details
    CryptFsConfig:
      type: object
      properties:
        passphrase:
          $ref: '#/components/schemas/Secret'
      description: Crypt filesystem configuration details
    SFTPFsConfig:
      type: object
      properties:
        endpoint:
          type: string
          description: 'remote SFTP endpoint as host:port'
        username:
          type: string
          description: you can specify a password or private key or both. In the latter case the private key will be tried first.
        password:
          $ref: '#/components/schemas/Secret'
        private_key:
          $ref: '#/components/schemas/Secret'
        fingerprints:
          type: array
          items:
            type: string
          description: 'SHA256 fingerprints to use for host key verification. If you don''t provide any fingerprint the remote host key will not be verified, this is a security risk'
        prefix:
          type: string
          description: Specifying a prefix you can restrict all operations to a given path within the remote SFTP server.
        disable_concurrent_reads:
          type: boolean
          description: Concurrent reads are safe to use and disabling them will degrade performance. Some servers automatically delete files once they are downloaded. Using concurrent reads is problematic with such servers.
        buffer_size:
          type: integer
          minimum: 0
          maximum: 16
          example: 2
          description: The size of the buffer (in MB) to use for transfers. By enabling buffering, the reads and writes, from/to the remote SFTP server, are split in multiple concurrent requests and this allows data to be transferred at a faster rate, over high latency networks, by overlapping round-trip times. With buffering enabled, resuming uploads is not supported and a file cannot be opened for both reading and writing at the same time. 0 means disabled.
    FilesystemConfig:
      type: object
      properties:
        provider:
          type: integer
          enum:
            - 0
            - 1
            - 2
            - 3
            - 4
            - 5
          description: |
            Providers:
              * `0` - Local filesystem
              * `1` - S3 Compatible Object Storage
              * `2` - Google Cloud Storage
              * `3` - Azure Blob Storage
              * `4` - Local filesystem encrypted
              * `5` - SFTP
        s3config:
          $ref: '#/components/schemas/S3Config'
        gcsconfig:
          $ref: '#/components/schemas/GCSConfig'
        azblobconfig:
          $ref: '#/components/schemas/AzureBlobFsConfig'
        cryptconfig:
          $ref: '#/components/schemas/CryptFsConfig'
        sftpconfig:
          $ref: '#/components/schemas/SFTPFsConfig'
      description: Storage filesystem details
    BaseVirtualFolder:
      type: object
      properties:
        id:
          type: integer
          format: int32
          minimum: 1
        name:
          type: string
          description: unique name for this virtual folder
        mapped_path:
          type: string
          description: absolute filesystem path to use as virtual folder
        description:
          type: string
          description: optional description
        used_quota_size:
          type: integer
          format: int64
        used_quota_files:
          type: integer
          format: int32
        last_quota_update:
          type: integer
          format: int64
          description: Last quota update as unix timestamp in milliseconds
        users:
          type: array
          items:
            type: string
          description: list of usernames associated with this virtual folder
        filesystem:
          $ref: '#/components/schemas/FilesystemConfig'
      description: Defines the filesystem for the virtual folder and the used quota limits. The same folder can be shared among multiple users and each user can have different quota limits or a different virtual path.
    VirtualFolder:
      allOf:
        - $ref: '#/components/schemas/BaseVirtualFolder'
        - type: object
          properties:
            virtual_path:
              type: string
            quota_size:
              type: integer
              format: int64
              description: 'Quota as size in bytes. 0 menas unlimited, -1 means included in user quota. Please note that quota is updated if files are added/removed via SFTPGo otherwise a quota scan or a manual quota update is needed'
            quota_files:
              type: integer
              format: int32
              description: 'Quota as number of files. 0 menas unlimited, , -1 means included in user quota. Please note that quota is updated if files are added/removed via SFTPGo otherwise a quota scan or a manual quota update is needed'
          required:
            - virtual_path
      description: 'A virtual folder is a mapping between a SFTPGo virtual path and a filesystem path outside the user home directory. The specified paths must be absolute and the virtual path cannot be "/", it must be a sub directory. The parent directory for the specified virtual path must exist. SFTPGo will try to automatically create any missing parent directory for the configured virtual folders at user login.'
    User:
      type: object
      properties:
        id:
          type: integer
          format: int32
          minimum: 1
        status:
          type: integer
          enum:
            - 0
            - 1
          description: |
            status:
              * `0` user is disabled, login is not allowed
              * `1` user is enabled
        username:
          type: string
          description: username is unique
        description:
          type: string
          description: 'optional description, for example the user full name'
        expiration_date:
          type: integer
          format: int64
          description: expiration date as unix timestamp in milliseconds. An expired account cannot login. 0 means no expiration
        password:
          type: string
          format: password
          description: password or public key/SSH user certificate are mandatory. If the password has no known hashing algo prefix it will be stored, by default, using bcrypt, argon2id is supported too. You can send a password hashed as bcrypt ($2a$ prefix), argon2id, pbkdf2 or unix crypt and it will be stored as is. For security reasons this field is omitted when you search/get users
        public_keys:
          type: array
          items:
            type: string
          description: a password or at least one public key/SSH user certificate are mandatory.
        home_dir:
          type: string
          description: path to the user home directory. The user cannot upload or download files outside this directory. SFTPGo tries to automatically create this folder if missing. Must be an absolute path
        virtual_folders:
          type: array
          items:
            $ref: '#/components/schemas/VirtualFolder'
          description: mapping between virtual SFTPGo paths and filesystem paths outside the user home directory. Supported for local filesystem only. If one or more of the specified folders are not inside the dataprovider they will be automatically created. You have to create the folder on the filesystem yourself
        uid:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
          description: 'if you run SFTPGo as root user, the created files and directories will be assigned to this uid. 0 means no change, the owner will be the user that runs SFTPGo. Ignored on windows'
        gid:
          type: integer
          format: int32
          minimum: 0
          maximum: 2147483647
          description: 'if you run SFTPGo as root user, the created files and directories will be assigned to this gid. 0 means no change, the group will be the one of the user that runs SFTPGo. Ignored on windows'
        max_sessions:
          type: integer
          format: int32
          description: Limit the sessions that a user can open. 0 means unlimited
        quota_size:
          type: integer
          format: int64
          description: Quota as size in bytes. 0 menas unlimited. Please note that quota is updated if files are added/removed via SFTPGo otherwise a quota scan or a manual quota update is needed
        quota_files:
          type: integer
          format: int32
          description: Quota as number of files. 0 menas unlimited. Please note that quota is updated if files are added/removed via SFTPGo otherwise a quota scan or a manual quota update is needed
        permissions:
          type: object
          items:
            $ref: '#/components/schemas/DirPermissions'
          minItems: 1
          example:
            /:
              - '*'
            /somedir:
              - list
              - download
        used_quota_size:
          type: integer
          format: int64
        used_quota_files:
          type: integer
          format: int32
        last_quota_update:
          type: integer
          format: int64
          description: Last quota update as unix timestamp in milliseconds
        upload_bandwidth:
          type: integer
          format: int32
          description: 'Maximum upload bandwidth as KB/s, 0 means unlimited'
        download_bandwidth:
          type: integer
          format: int32
          description: 'Maximum download bandwidth as KB/s, 0 means unlimited'
        last_login:
          type: integer
          format: int64
          description: Last user login as unix timestamp in milliseconds. It is saved at most once every 10 minutes
        filters:
          $ref: '#/components/schemas/UserFilters'
        filesystem:
          $ref: '#/components/schemas/FilesystemConfig'
        additional_info:
          type: string
          description: Free form text field for external systems
    AdminFilters:
      type: object
      properties:
        allow_list:
          type: array
          items:
            type: string
          description: 'only clients connecting from these IP/Mask are allowed. IP/Mask must be in CIDR notation as defined in RFC 4632 and RFC 4291, for example "192.0.2.0/24" or "2001:db8::/32"'
          example:
            - 192.0.2.0/24
            - '2001:db8::/32'
    Admin:
      type: object
      properties:
        id:
          type: integer
          format: int32
          minimum: 1
        status:
          type: integer
          enum:
            - 0
            - 1
          description: |
            status:
              * `0` user is disabled, login is not allowed
              * `1` user is enabled
        username:
          type: string
          description: username is unique
        description:
          type: string
          description: 'optional description, for example the admin full name'
        password:
          type: string
          format: password
          description: Admin password. For security reasons this field is omitted when you search/get admins
        email:
          type: string
          format: email
        permissions:
          type: array
          items:
            $ref: '#/components/schemas/AdminPermissions'
        filters:
          $ref: '#/components/schemas/AdminFilters'
        additional_info:
          type: string
          description: Free form text field
    Transfer:
      type: object
      properties:
        operation_type:
          type: string
          enum:
            - upload
            - download
          description: |
            Operations:
              * `upload`
              * `download`
        path:
          type: string
          description: file path for the upload/download
        start_time:
          type: integer
          format: int64
          description: start time as unix timestamp in milliseconds
        size:
          type: integer
          format: int64
          description: bytes transferred
    ConnectionStatus:
      type: object
      properties:
        username:
          type: string
          description: connected username
        connection_id:
          type: string
          description: unique connection identifier
        client_version:
          type: string
          description: client version
        remote_address:
          type: string
          description: Remote address for the connected client
        connection_time:
          type: integer
          format: int64
          description: connection time as unix timestamp in milliseconds
        command:
          type: string
          description: Last SSH/FTP command or WebDAV method
        last_activity:
          type: integer
          format: int64
          description: last client activity as unix timestamp in milliseconds
        protocol:
          type: string
          enum:
            - SFTP
            - SCP
            - SSH
            - FTP
            - DAV
        active_transfers:
          type: array
          items:
            $ref: '#/components/schemas/Transfer'
    QuotaScan:
      type: object
      properties:
        username:
          type: string
          description: username with an active scan
        start_time:
          type: integer
          format: int64
          description: scan start time as unix timestamp in milliseconds
    FolderQuotaScan:
      type: object
      properties:
        name:
          type: string
          description: folder name with an active scan
        start_time:
          type: integer
          format: int64
          description: scan start time as unix timestamp in milliseconds
    SSHHostKey:
      type: object
      properties:
        path:
          type: string
        fingerprint:
          type: string
    SSHBinding:
      type: object
      properties:
        address:
          type: string
          description: TCP address the server listen on
        port:
          type: integer
          description: the port used for serving requests
        apply_proxy_config:
          type: boolean
          description: 'apply the proxy configuration, if any'
    WebDAVBinding:
      type: object
      properties:
        address:
          type: string
          description: TCP address the server listen on
        port:
          type: integer
          description: the port used for serving requests
        enable_https:
          type: boolean
        client_auth_type:
          type: integer
          description: 1 means that client certificate authentication is required in addition to HTTP basic authentication
    FTPDBinding:
      type: object
      properties:
        address:
          type: string
          description: TCP address the server listen on
        port:
          type: integer
          description: the port used for serving requests
        apply_proxy_config:
          type: boolean
          description: 'apply the proxy configuration, if any'
        tls_mode:
          type: integer
          enum:
            - 0
            - 1
            - 2
          description: |
            * `0` - clear or explicit TLS * `1` - explicit TLS required * `2` - implicit TLS
        force_passive_ip:
          type: string
          description: External IP address to expose for passive connections
        client_auth_type:
          type: integer
          description: 1 means that client certificate authentication is required in addition to FTP authentication
    SSHServiceStatus:
      type: object
      properties:
        is_active:
          type: boolean
        bindings:
          type: array
          items:
            $ref: '#/components/schemas/SSHBinding'
          nullable: true
        host_keys:
          type: array
          items:
            $ref: '#/components/schemas/SSHHostKey'
          nullable: true
        ssh_commands:
          type: array
          items:
            type: string
    FTPPassivePortRange:
      type: object
      properties:
        start:
          type: integer
        end:
          type: integer
    FTPServiceStatus:
      type: object
      properties:
        is_active:
          type: boolean
        bindings:
          type: array
          items:
            $ref: '#/components/schemas/FTPDBinding'
          nullable: true
        passive_port_range:
          $ref: '#/components/schemas/FTPPassivePortRange'
    WebDAVServiceStatus:
      type: object
      properties:
        is_active:
          type: boolean
        bindings:
          type: array
          items:
            $ref: '#/components/schemas/WebDAVBinding'
          nullable: true
    DataProviderStatus:
      type: object
      properties:
        is_active:
          type: boolean
        driver:
          type: string
        error:
          type: string
    ServicesStatus:
      type: object
      properties:
        ssh:
          $ref: '#/components/schemas/SSHServiceStatus'
        ftp:
          $ref: '#/components/schemas/FTPServiceStatus'
        webdav:
          $ref: '#/components/schemas/WebDAVServiceStatus'
        data_provider:
          $ref: '#/components/schemas/DataProviderStatus'
        defender:
          type: object
          properties:
            is_active:
              type: boolean
    BanStatus:
      type: object
      properties:
        date_time:
          type: string
          format: date-time
          nullable: true
          description: if null the host is not banned
    ScoreStatus:
      type: object
      properties:
        score:
          type: integer
          description: if 0 the host is not listed
    BackupData:
      type: object
      properties:
        users:
          type: array
          items:
            $ref: '#/components/schemas/User'
        folders:
          type: array
          items:
            $ref: '#/components/schemas/BaseVirtualFolder'
        admins:
          type: array
          items:
            $ref: '#/components/schemas/Admin'
        version:
          type: integer
    PwdChange:
      type: object
      properties:
        current_password:
          type: string
        new_password:
          type: string
    ApiResponse:
      type: object
      properties:
        message:
          type: string
          description: 'message, can be empty'
        error:
          type: string
          description: error description if any
    VersionInfo:
      type: object
      properties:
        version:
          type: string
        build_date:
          type: string
        commit_hash:
          type: string
        features:
          type: array
          items:
            type: string
          description: 'Features for the current build. Available features are "portable", "bolt", "mysql", "sqlite", "pgsql", "s3", "gcs", "metrics". If a feature is available it has a "+" prefix, otherwise a "-" prefix'
    Token:
      type: object
      properties:
        access_token:
          type: string
        expires_at:
          type: string
          format: date-time
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
