openapi: 3.0.3
info:
  title: STCP DirectLink API
  version: v2
  description: |
    Public HTTP API specification for STCP DirectLink.

    Replace the example host with the host provided by your environment administrator. Use HTTPS in production. Use secure links returned by the API in full, without changing their parameters.

    Protected routes accept a Bearer token in the Authorization header or the __Host-dirl_session session cookie. If both are sent, the Authorization header takes precedence.
  contact:
    name: Service administrator
servers:
  - url: https://api.exemplo.com/directlink/v2
    description: Example host; replace with your environment's address.
tags:
  - name: Availability
  - name: Authentication
  - name: Session
  - name: Transfers
  - name: Reports
  - name: Single Sign-On
paths:
  /healthcheck:
    get:
      tags:
        - Availability
      summary: Check availability
      operationId: getHealthcheck
      security: []
      responses:
        '200':
          description: Service is accessible.
          headers:
            Cache-Control:
              description: Prevents caching of the response.
              schema:
                type: string
                enum:
                  - no-store
          content:
            application/json:
              schema:
                type: object
                required:
                  - status
                  - service
                  - timestamp
                  - uptime_seconds
                properties:
                  status:
                    type: string
                    enum:
                      - ok
                  service:
                    type: string
                    enum:
                      - STCPDirectLink
                  timestamp:
                    type: string
                    format: date-time
                    description: UTC check time in RFC 3339 format.
                  uptime_seconds:
                    type: integer
                    format: int64
                    minimum: 0
                    description: Seconds since the HTTP service started.
              example:
                status: ok
                service: STCPDirectLink
                timestamp: '2026-10-16T19:29:23Z'
                uptime_seconds: 86400
  /auth/login:
    get:
      tags:
        - Authentication
      summary: Start a local session
      description: |
        Authenticates using HTTP Basic. If MFA is required, the `206` response includes a secure link to complete the challenge. Follow the full returned link; do not reconstruct its parameters.
        When Cloudflare Turnstile validation is enabled, send the widget token in
        the `CF-Turnstile-Response` header; it is validated before the
        credentials.
      operationId: loginGet
      security:
        - basicAuth: []
      parameters:
        - $ref: '#/components/parameters/TurnstileResponse'
      responses:
        '200':
          description: Login completed; the session is established through a cookie.
          headers:
            Set-Cookie:
              $ref: '#/components/headers/SessionCookie'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '206':
          description: An additional MFA step is required.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MfaChallengeResponse'
        '400':
          description: Missing credentials or missing or invalid `CF-Turnstile-Response` header.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Access denied or Turnstile token rejected (invalid, expired, or already used).
        '503':
          description: The Turnstile token could not be validated with Cloudflare.
    post:
      tags:
        - Authentication
      summary: Start a local session
      description: |
        Authenticates using HTTP Basic. If MFA is required, the `206` response includes a secure link to complete the challenge. Follow the full returned link; do not reconstruct its parameters.
        When Cloudflare Turnstile validation is enabled, send the widget token in
        the `CF-Turnstile-Response` header; it is validated before the
        credentials.
      operationId: loginPost
      security:
        - basicAuth: []
      parameters:
        - $ref: '#/components/parameters/TurnstileResponse'
      responses:
        '200':
          description: Login completed; the session is established through a cookie.
          headers:
            Set-Cookie:
              $ref: '#/components/headers/SessionCookie'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '206':
          description: An additional MFA step is required.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MfaChallengeResponse'
        '400':
          description: Missing credentials or missing or invalid `CF-Turnstile-Response` header.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Access denied or Turnstile token rejected (invalid, expired, or already used).
        '503':
          description: The Turnstile token could not be validated with Cloudflare.
  /auth/mfa:
    get:
      tags:
        - Authentication
      summary: 'Validate an MFA challenge (code in the query string)'
      description: 'Validates the second factor requested by login (`status` `1` or `2` in the `206` response). Use the full URL received in `linkURL`. Prefer `POST`, with the code in the form.'
      operationId: getMfaChallenge
      security: []
      parameters:
        - name: p
          in: query
          required: true
          schema:
            type: string
          description: 'PIN sent by email or SMS, or TOTP code.'
      responses:
        '200':
          description: 'Second factor validated; the session is established through a cookie.'
          headers:
            Set-Cookie:
              $ref: '#/components/headers/SessionCookie'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '400':
          description: 'Invalid or expired link, or missing `p` field.'
        '403':
          description: 'Invalid TOTP code, user locked or not found.'
        '405':
          description: 'Method other than `GET` and `POST`.'
    post:
      tags:
        - Authentication
      summary: 'Validate an MFA challenge'
      description: 'Validates the second factor requested by login (`status` `1` or `2` in the `206` response). Use the full URL received in `linkURL`. Prefer `POST`, with the code in the form.'
      operationId: postMfaChallenge
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [p]
              properties:
                p:
                  type: string
                  description: 'PIN sent by email or SMS, or TOTP code.'
      responses:
        '200':
          description: 'Second factor validated; the session is established through a cookie.'
          headers:
            Set-Cookie:
              $ref: '#/components/headers/SessionCookie'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '400':
          description: 'Invalid or expired link, or missing `p` field.'
        '403':
          description: 'Invalid TOTP code, user locked or not found.'
        '405':
          description: 'Method other than `GET` and `POST`.'
  /auth/mfa/register:
    get:
      tags:
        - Authentication
      summary: 'Confirm TOTP registration (code in the query string)'
      description: 'Confirms the TOTP registration requested by login (`status` `3` in the `206` response). Send the code generated by the authenticator app with the secret received. Does not establish a session: after registration, log in again.'
      operationId: getMfaRegistration
      security: []
      parameters:
        - name: p
          in: query
          required: true
          schema:
            type: string
          description: 'TOTP code generated by the authenticator app.'
      responses:
        '200':
          description: 'TOTP registered. Does not establish a session.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MfaRegisterResponse'
        '400':
          description: 'Invalid or expired link, or missing `p` field.'
        '403':
          description: 'Invalid TOTP code or failure to store the secret.'
        '405':
          description: 'Method other than `GET` and `POST`.'
    post:
      tags:
        - Authentication
      summary: 'Confirm TOTP registration'
      description: 'Confirms the TOTP registration requested by login (`status` `3` in the `206` response). Send the code generated by the authenticator app with the secret received. Does not establish a session: after registration, log in again.'
      operationId: postMfaRegistration
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [p]
              properties:
                p:
                  type: string
                  description: 'TOTP code generated by the authenticator app.'
      responses:
        '200':
          description: 'TOTP registered. Does not establish a session.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MfaRegisterResponse'
        '400':
          description: 'Invalid or expired link, or missing `p` field.'
        '403':
          description: 'Invalid TOTP code or failure to store the secret.'
        '405':
          description: 'Method other than `GET` and `POST`.'
  /auth/token:
    post:
      tags:
        - Authentication
      summary: Issue a token or exchange a source token
      description: |
        Accepts password grant and token exchange. The password grant may be disabled in the environment and is not part of OAuth 2.1. For token exchange, the `provider` form field takes precedence over `X-STCPDIRECTLINK-JWT-ISSUER`. This header does not authenticate protected requests.
      operationId: postAuthToken
      security: []
      parameters:
        - $ref: '#/components/parameters/JwtIssuer'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              oneOf:
                - $ref: '#/components/schemas/PasswordGrantRequest'
                - $ref: '#/components/schemas/TokenExchangeRequest'
      responses:
        '200':
          description: Access token issued.
          headers:
            Cache-Control:
              schema:
                type: string
              example: no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResponse'
        '400':
          $ref: '#/components/responses/OAuthError'
  /oauth2/token:
    post:
      tags:
        - Authentication
      summary: Issue a token or exchange a source token
      description: Alias for `POST /auth/token`.
      operationId: postOauth2Token
      security: []
      parameters:
        - $ref: '#/components/parameters/JwtIssuer'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              oneOf:
                - $ref: '#/components/schemas/PasswordGrantRequest'
                - $ref: '#/components/schemas/TokenExchangeRequest'
      responses:
        '200':
          description: Access token issued.
          headers:
            Cache-Control:
              schema:
                type: string
              example: no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResponse'
        '400':
          $ref: '#/components/responses/OAuthError'
  /auth/firstaccess:
    get:
      tags:
        - Authentication
      summary: Initiate first access
      description: |
        When Cloudflare Turnstile validation is enabled, send the widget token in
        the `CF-Turnstile-Response` header; it is validated before processing.
      operationId: getFirstAccess
      security: []
      parameters:
        - $ref: '#/components/parameters/Username'
        - $ref: '#/components/parameters/TurnstileResponse'
      responses:
        '200':
          description: Secure link in `linkURL`; PIN sent to the user by email or SMS.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecureLinkResponse'
        '400':
          description: Missing parameter or missing or invalid `CF-Turnstile-Response` header.
        '403':
          description: Access denied or Turnstile token rejected (invalid, expired, or already used).
        '503':
          description: The Turnstile token could not be validated with Cloudflare.
  /auth/forget:
    get:
      tags:
        - Authentication
      summary: Initiate password recovery
      description: |
        When Cloudflare Turnstile validation is enabled, send the widget token in
        the `CF-Turnstile-Response` header; it is validated before processing.
      operationId: getPasswordRecovery
      security: []
      parameters:
        - $ref: '#/components/parameters/Username'
        - $ref: '#/components/parameters/TurnstileResponse'
      responses:
        '200':
          description: Secure link in `linkURL`; PIN sent to the user by email or SMS.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecureLinkResponse'
        '400':
          description: Missing parameter or missing or invalid `CF-Turnstile-Response` header.
        '403':
          description: Access denied or Turnstile token rejected (invalid, expired, or already used).
        '503':
          description: The Turnstile token could not be validated with Cloudflare.
  /auth/change:
    post:
      tags:
        - Authentication
      summary: Complete password change
      description: |
        Use the full `linkURL` returned by `/auth/firstaccess` or `/auth/forget`, with `k` in the URL. The link carries protected identification and validity parameters; do not construct them manually.
        Accepts only `POST`. Send `p` and `z` in the form body, never in the URL.
      operationId: postPasswordChange
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - p
                - z
              properties:
                p:
                  type: string
                  description: PIN or code required by the flow.
                z:
                  type: string
                  format: password
                  description: New password.
      responses:
        '200':
          description: Password changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperationResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          description: The password change was refused.
        '405':
          description: Method other than `POST`.
  /auth/logout:
    get:
      tags:
        - Session
      summary: End a session
      operationId: getLogout
      security:
        - bearerAuth: []
        - sessionCookie: []
      responses:
        '200':
          description: Session ended.
          headers:
            Set-Cookie:
              $ref: '#/components/headers/ClearedSessionCookie'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
        - Session
      summary: End a session
      operationId: postLogout
      security:
        - bearerAuth: []
        - sessionCookie: []
      responses:
        '200':
          description: Session ended.
          headers:
            Set-Cookie:
              $ref: '#/components/headers/ClearedSessionCookie'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /upload:
    post:
      tags:
        - Transfers
      summary: Upload a file
      operationId: postUpload
      security:
        - bearerAuth: []
        - sessionCookie: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/MultipartUpload'
            encoding:
              file:
                contentType: application/octet-stream
          application/octet-stream:
            schema:
              type: string
              format: binary
      parameters:
        - in: header
          name: X-STCPDIRECTLINK-FILENAME
          required: false
          description: Required when the body is application/octet-stream.
          schema:
            type: string
        - in: header
          name: X-STCPDIRECTLINK-DESTINATION
          required: false
          schema:
            type: string
        - in: header
          name: X-STCPDIRECTLINK-EMAIL
          required: false
          schema:
            type: string
        - in: header
          name: X-STCPDIRECTLINK-MOBILE
          required: false
          schema:
            type: string
        - in: header
          name: X-STCPDIRECTLINK-HASH
          required: false
          schema:
            type: string
        - in: header
          name: X-STCPDIRECTLINK-EMAIL-FROM
          required: false
          schema:
            type: string
        - in: header
          name: X-STCPDIRECTLINK-INFO
          required: false
          schema:
            type: string
      responses:
        '200':
          description: File received.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          description: "Connection blocked for the user: user locked, outside the allowed time window or rejected by the external validation program."
  /download/list:
    get:
      tags:
        - Transfers
      summary: List available files
      operationId: getDownloadList
      security:
        - bearerAuth: []
        - sessionCookie: []
      parameters:
        - $ref: '#/components/parameters/Page'
      responses:
        '200':
          description: Page of available files.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileListResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /download/list/backup:
    get:
      tags:
        - Transfers
      summary: List backup files
      operationId: getBackupDownloadList
      security:
        - bearerAuth: []
        - sessionCookie: []
      parameters:
        - $ref: '#/components/parameters/Page'
      responses:
        '200':
          description: Page of backup files.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileListResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /download/file:
    get:
      tags:
        - Transfers
      summary: Download a listed file
      description: |
        Use the full `linkURL` URL from the listing, with the Bearer token or the session cookie of the same user who made the listing. The link alone does not give access to the file.
      operationId: getDownloadFile
      security:
        - bearerAuth: []
        - sessionCookie: []
      responses:
        '200':
          description: File contents.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '400':
          description: Missing credential.
        '401':
          description: Invalid or expired token.
        '403':
          description: The token belongs to another user, download is disabled or access was blocked.
        '404':
          description: File or link not found.
  /download/file/backup:
    get:
      tags:
        - Transfers
      summary: Download a backup file
      description: |
        Use the full `linkURL` URL from the backup listing, with the Bearer token or the session cookie of the same user who made the listing.
      operationId: getBackupDownloadFile
      security:
        - bearerAuth: []
        - sessionCookie: []
      responses:
        '200':
          description: Backup file contents.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '400':
          description: Missing credential.
        '401':
          description: Invalid or expired token.
        '403':
          description: The token belongs to another user, download is disabled or access was blocked.
        '404':
          description: File or link not found.
  /download:
    get:
      tags:
        - Transfers
      summary: Download a shared file
      description: |
        Open the full secure URL sent to the recipient. When the link requires a PIN, send it as the `p` parameter without modifying the link's other parameters.
      operationId: getSharedDownload
      security: []
      parameters:
        - in: query
          name: p
          required: false
          description: PIN required by the secure link, when applicable.
          schema:
            type: string
      responses:
        '200':
          description: File contents.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '404':
          description: File or link not found.
  /download/pin:
    get:
      tags:
        - Transfers
      summary: Send a PIN and obtain a download link
      description: Use the full secure URL issued to initiate PIN delivery.
      operationId: getDownloadPin
      security: []
      responses:
        '200':
          description: PIN sent; the response contains the download link.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DownloadPinResponse'
  /report:
    get:
      tags:
        - Reports
      summary: Query the transfer report
      operationId: getReport
      security:
        - bearerAuth: []
        - sessionCookie: []
      parameters:
        - $ref: '#/components/parameters/Page'
        - in: query
          name: days
          required: false
          description: Query window in days; defaults to 1.
          schema:
            type: integer
            default: 1
        - in: query
          name: filterdirection
          required: true
          description: Transfer type; 5 = completed downloads (event STCPEVTENDSENDFILE), 7 = completed uploads (event STCPEVTENDRECEIVEFILE). Other values return 400.
          schema:
            type: integer
            enum:
              - 5
              - 7
        - in: query
          name: filterfile
          required: false
          description: Filters by file name.
          schema:
            type: string
      responses:
        '200':
          description: Transfer records.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /sso/login:
    get:
      tags:
        - Single Sign-On
      summary: Start federated login
      description: Starts the browser flow and redirects to the provider.
      operationId: getSsoLogin
      security: []
      parameters:
        - $ref: '#/components/parameters/Provider'
      responses:
        '302':
          description: Redirect to the identity provider.
          headers:
            Location:
              schema:
                type: string
                format: uri
  /sso/logout:
    get:
      tags:
        - Single Sign-On
      summary: Start federated logout
      operationId: getSsoLogout
      security:
        - bearerAuth: []
        - sessionCookie: []
      parameters:
        - $ref: '#/components/parameters/Provider'
      responses:
        '302':
          description: Redirect to the provider or logout destination.
          headers:
            Location:
              schema:
                type: string
                format: uri
        '401':
          $ref: '#/components/responses/Unauthorized'
  /sso/oauth2/cb:
    get:
      tags:
        - Single Sign-On
      summary: Receive an OAuth 2.0 and 2.1/OpenID Connect callback
      description: Called by the provider as part of the login flow.
      operationId: getOauthCallback
      security: []
      parameters:
        - in: query
          name: state
          required: true
          schema:
            type: string
        - in: query
          name: code
          required: true
          schema:
            type: string
      responses:
        '302':
          description: Redirect after processing the callback.
          headers:
            Location:
              schema:
                type: string
                format: uri
    post:
      tags:
        - Single Sign-On
      summary: Receive an OAuth 2.0 and 2.1/OpenID Connect callback
      operationId: postOauthCallback
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - state
                - code
              properties:
                state:
                  type: string
                code:
                  type: string
      responses:
        '302':
          description: Redirect after processing the callback.
          headers:
            Location:
              schema:
                type: string
                format: uri
  /sso/oauth2/logout/cb:
    get:
      tags:
        - Single Sign-On
      summary: Receive an OAuth 2.0 logout callback
      operationId: getOauthLogoutCallback
      security: []
      parameters:
        - in: query
          name: state
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/Provider'
      responses:
        '302':
          description: Redirect after processing the callback.
          headers:
            Location:
              schema:
                type: string
                format: uri
    post:
      tags:
        - Single Sign-On
      summary: Receive an OAuth 2.0 logout callback
      operationId: postOauthLogoutCallback
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - state
                - provider
              properties:
                state:
                  type: string
                provider:
                  type: string
      responses:
        '302':
          description: Redirect after processing the callback.
          headers:
            Location:
              schema:
                type: string
                format: uri
  /sso/saml2/acs:
    post:
      tags:
        - Single Sign-On
      summary: Receive a SAML assertion
      description: ACS endpoint called by the SAML provider via HTTP POST.
      operationId: postSamlAcs
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - SAMLResponse
              properties:
                SAMLResponse:
                  type: string
                  description: Base64-encoded SAML assertion.
                RelayState:
                  type: string
      responses:
        '302':
          description: Redirect after processing the assertion.
          headers:
            Location:
              schema:
                type: string
                format: uri
  /sso/saml2/slo:
    get:
      tags:
        - Single Sign-On
      summary: Receive a SAML logout message
      operationId: getSamlSlo
      security: []
      parameters:
        - in: query
          name: SAMLResponse
          required: false
          schema:
            type: string
        - in: query
          name: RelayState
          required: false
          schema:
            type: string
      responses:
        '302':
          description: Redirect after processing logout.
          headers:
            Location:
              schema:
                type: string
                format: uri
    post:
      tags:
        - Single Sign-On
      summary: Receive a SAML logout message
      operationId: postSamlSlo
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                SAMLResponse:
                  type: string
                RelayState:
                  type: string
      responses:
        '302':
          description: Redirect after processing logout.
          headers:
            Location:
              schema:
                type: string
                format: uri
  /sso/saml2/metadata:
    get:
      tags:
        - Single Sign-On
      summary: Get SAML metadata by query
      operationId: getSamlMetadataByQuery
      security: []
      parameters:
        - $ref: '#/components/parameters/Provider'
      responses:
        '200':
          description: Provider XML metadata.
          content:
            application/xml:
              schema:
                type: string
  /sso/saml2/metadata/{provider}:
    get:
      tags:
        - Single Sign-On
      summary: Get SAML metadata by path
      operationId: getSamlMetadataByPath
      security: []
      parameters:
        - name: provider
          in: path
          required: true
          description: Registered SAML provider identifier.
          schema:
            type: string
      responses:
        '200':
          description: Provider XML metadata.
          content:
            application/xml:
              schema:
                type: string
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
    bearerAuth:
      type: http
      scheme: bearer
      description: Access token issued by an OAuth endpoint.
    sessionCookie:
      type: apiKey
      in: cookie
      name: __Host-dirl_session
      description: Session cookie issued after local login or SSO.
  headers:
    SessionCookie:
      description: Secure session cookie returned after authentication.
      schema:
        type: string
      example: __Host-dirl_session=<token>; Path=/; Secure; HttpOnly; SameSite=Strict
    ClearedSessionCookie:
      description: Session cookie cleared when applicable.
      schema:
        type: string
  parameters:
    TurnstileResponse:
      in: header
      name: CF-Turnstile-Response
      required: false
      description: Token generated by the Cloudflare Turnstile widget. Required when `turnstileEnable` is enabled in the configuration; ignored otherwise. The token is single-use.
      schema:
        type: string
        maxLength: 2048
    JwtIssuer:
      in: header
      name: X-STCPDIRECTLINK-JWT-ISSUER
      required: false
      description: Provider used to validate the source JWT in token exchange.
      schema:
        type: string
    Username:
      in: query
      name: u
      required: true
      description: Account identifier.
      schema:
        type: string
    Page:
      in: query
      name: page
      required: false
      description: Page index; defaults to 0.
      schema:
        type: integer
        default: 0
    Provider:
      in: query
      name: provider
      required: true
      description: Configured provider identifier.
      schema:
        type: string
  requestBodies:
    TokenRequest:
      required: true
      content:
        application/x-www-form-urlencoded:
          schema:
            oneOf:
              - $ref: '#/components/schemas/PasswordGrantRequest'
              - $ref: '#/components/schemas/TokenExchangeRequest'
  responses:
    BadRequest:
      description: Invalid request or parameter.
    Unauthorized:
      description: Credential or token not accepted.
    OAuthError:
      description: Grant or source token validation failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/OAuthError'
  schemas:
    OperationResponse:
      type: object
      properties:
        status:
          type: integer
          example: 0
        description:
          type: string
        apiver:
          type: string
          example: v2 (9.0.1)
        user:
          type: string
        length:
          type: integer
          format: int64
        time:
          type: string
          format: date-time
    LoginResponse:
      type: object
      properties:
        status:
          type: integer
          example: 0
        description:
          type: string
        apiver:
          type: string
          example: v2 (9.0.1)
        user:
          type: string
        urllink:
          type: string
          format: uri
        time:
          type: string
          format: date-time
    MfaChallengeResponse:
      type: object
      properties:
        status:
          type: integer
          enum: [1, 2, 3]
          description: 'MFA step: `1` PIN by email or SMS (`/auth/mfa`), `2` registered TOTP (`/auth/mfa`), `3` TOTP registration (`/auth/mfa/register`).'
        description:
          type: string
        apiver:
          type: string
          example: v2 (9.0.1)
        user:
          type: string
        linkURL:
          type: string
          format: uri
          description: 'Full secure URL to complete the step.'
        secret:
          type: string
          format: password
          description: 'Only in `status` `3`: TOTP secret in Base32. Empty in `status` `2`; absent in `status` `1`. Sensitive data.'
        qrcode:
          type: string
          description: 'Only in `status` `3`: secret QR code, 200 × 200 PNG image in URL-safe Base64 (RFC 4648, with `-` and `_`). Convert it to standard Base64 to use in `data:image/png;base64,`. Empty in `status` `2`; absent in `status` `1`.'
        time:
          type: string
          format: date-time
    MfaRegisterResponse:
      type: object
      properties:
        status:
          type: integer
          example: 0
        description:
          type: string
          example: handlerAuthMfaRegister:succsessfully
        apiver:
          type: string
          example: v2 (9.0.1)
        user:
          type: string
        length:
          type: integer
          description: 'Always `0`.'
        time:
          type: string
    SecureLinkResponse:
      type: object
      properties:
        status:
          type: integer
          example: 0
        description:
          type: string
        apiver:
          type: string
          example: v2 (9.0.1)
        user:
          type: string
        linkURL:
          type: string
          format: uri
        time:
          type: string
          format: date-time
    PasswordGrantRequest:
      type: object
      required:
        - grant_type
        - username
        - password
      properties:
        grant_type:
          type: string
          enum:
            - password
        username:
          type: string
        password:
          type: string
          format: password
    TokenExchangeRequest:
      type: object
      required:
        - grant_type
        - subject_token_type
        - subject_token
      properties:
        grant_type:
          type: string
          enum:
            - urn:ietf:params:oauth:grant-type:token-exchange
        subject_token_type:
          type: string
          enum:
            - urn:ietf:params:oauth:token-type:jwt
        subject_token:
          type: string
          description: Source JWT.
        provider:
          type: string
          description: Provider that validates the token; takes precedence over the equivalent header.
    TokenResponse:
      type: object
      required:
        - access_token
        - issued_token_type
        - token_type
        - expires_in
        - scope
      properties:
        access_token:
          type: string
        issued_token_type:
          type: string
          enum:
            - urn:ietf:params:oauth:token-type:access_token
        token_type:
          type: string
          example: Bearer
        expires_in:
          type: integer
          format: int64
          description: Token lifetime in seconds; varies by instance.
        scope:
          type: string
          description: Configured API URI; does not represent a list of permissions.
    OAuthError:
      type: object
      properties:
        error:
          type: integer
          description: Numeric code of the reported condition.
        error_description:
          type: string
        error_uri:
          type: string
          format: uri
    MultipartUpload:
      type: object
      required:
        - file
      properties:
        file:
          type: string
          format: binary
        d:
          type: string
          description: Recipient or destination user.
        m:
          type: string
          description: Email associated with the transfer.
        c:
          type: string
          description: Mobile phone associated with the transfer.
        h:
          type: string
          description: Expected SHA-256 hash of the file.
        n:
          type: string
          description: Sender identifier or email.
        i:
          type: string
          description: Additional transfer information.
    UploadResponse:
      allOf:
        - $ref: '#/components/schemas/OperationResponse'
        - type: object
          properties:
            id:
              type: string
            destination:
              type: string
            length:
              type: integer
              format: int64
            linkURL:
              type: array
              items:
                type: string
                format: uri
    FileListResponse:
      allOf:
        - $ref: '#/components/schemas/OperationResponse'
        - type: object
          properties:
            files:
              type: array
              items:
                $ref: '#/components/schemas/FileEntry'
            page_next:
              type: string
    FileEntry:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        length:
          type: integer
          format: int64
        modified:
          type: integer
          format: int64
          description: Unix time in milliseconds.
        linkURL:
          type: string
          format: uri
          description: Signed link; use the full URL.
    DownloadPinResponse:
      allOf:
        - $ref: '#/components/schemas/OperationResponse'
        - type: object
          properties:
            email:
              type: string
            phone:
              type: string
            file:
              type: string
            linkURL:
              type: string
              format: uri
    ReportResponse:
      allOf:
        - $ref: '#/components/schemas/OperationResponse'
        - type: object
          properties:
            page:
              type: integer
            logs:
              type: array
              items:
                type: object
                additionalProperties: true
