openapi: 3.1.0
info:
  title: Quub Exchange - Document Management Service
  version: 2.0.0
  description:
    "Document management, publication, and electronic signature service.

    Supports multi-tenant storage, audit logging, and signature verification (eIDAS, UAE Pass, DocuSign, etc.).

    "
servers:
  - url: https://api.quub.exchange/v2
    description: Production API
  - url: https://api.sandbox.quub.exchange/v2
    description: Sandbox API
tags:
  - name: Documents
    description: Upload, retrieve, and manage organization documents.
  - name: ESignatures
    description: Electronic signature requests and workflow management.
  - name: Publications
    description: Publish and distribute finalized documents.
paths:
  /orgs/{orgId}/documents:
    get:
      tags:
        - Documents
      summary: List documents
      operationId: listDocuments
      security:
        - oauth2:
            - read:documents
        - apiKey: []
      parameters:
        - $ref: ./common/components.yaml#/components/parameters/orgId
        - $ref: ./common/components.yaml#/components/parameters/orgIdHeader
        - $ref: ./common/pagination.yaml#/components/parameters/cursor
        - $ref: ./common/pagination.yaml#/components/parameters/limit
        - name: status
          in: query
          schema:
            type: string
            enum:
              - DRAFT
              - REVIEW
              - PUBLISHED
              - ARCHIVED
        - name: type
          in: query
          schema:
            type: string
            enum:
              - PDF
              - DOCX
              - IMAGE
              - XLSX
              - JSON
      responses:
        "400":
          $ref: ./common/responses.yaml#/components/responses/BadRequest
        "401":
          $ref: ./common/responses.yaml#/components/responses/Unauthorized
        "500":
          $ref: ./common/responses.yaml#/components/responses/InternalServerError
        "200":
          description: List of documents
          content:
            application/json:
              schema:
                allOf:
                  - $ref: ./common/pagination.yaml#/components/schemas/PageResponse
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/Document"
        "403":
          $ref: ./common/responses.yaml#/components/responses/Forbidden
    post:
      tags:
        - Documents
      summary: Upload a new document
      operationId: uploadDocument
      security:
        - oauth2:
            - write:documents
        - apiKey: []
      parameters:
        - $ref: ./common/components.yaml#/components/parameters/orgId
        - $ref: ./common/components.yaml#/components/parameters/orgIdHeader
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
                - name
              properties:
                file:
                  type: string
                  format: binary
                name:
                  type: string
                type:
                  type: string
                  enum:
                    - PDF
                    - DOCX
                    - IMAGE
                    - XLSX
                    - JSON
                tags:
                  type: array
                  items:
                    type: string
                linkedProjectId:
                  type: string
                  format: uuid
      responses:
        "400":
          $ref: ./common/responses.yaml#/components/responses/BadRequest
        "401":
          $ref: ./common/responses.yaml#/components/responses/Unauthorized
        "500":
          $ref: ./common/responses.yaml#/components/responses/InternalServerError
        "201":
          description: Document uploaded successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Document"
        "403":
          $ref: ./common/responses.yaml#/components/responses/Forbidden
  /orgs/{orgId}/documents/{documentId}:
    get:
      tags:
        - Documents
      summary: Get document details
      operationId: getDocument
      security:
        - oauth2:
            - read:documents
        - apiKey: []
      parameters:
        - $ref: ./common/components.yaml#/components/parameters/orgId
        - $ref: ./common/components.yaml#/components/parameters/orgIdHeader
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "400":
          $ref: ./common/responses.yaml#/components/responses/BadRequest
        "401":
          $ref: ./common/responses.yaml#/components/responses/Unauthorized
        "500":
          $ref: ./common/responses.yaml#/components/responses/InternalServerError
        "200":
          description: Document details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Document"
        "403":
          $ref: ./common/responses.yaml#/components/responses/Forbidden
    patch:
      tags:
        - Documents
      summary: Update document metadata or status
      operationId: updateDocument
      security:
        - oauth2:
            - write:documents
        - apiKey: []
      parameters:
        - $ref: ./common/components.yaml#/components/parameters/orgId
        - $ref: ./common/components.yaml#/components/parameters/orgIdHeader
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                status:
                  type: string
                  enum:
                    - DRAFT
                    - REVIEW
                    - PUBLISHED
                    - ARCHIVED
                tags:
                  type: array
                  items:
                    type: string
      responses:
        "400":
          $ref: ./common/responses.yaml#/components/responses/BadRequest
        "401":
          $ref: ./common/responses.yaml#/components/responses/Unauthorized
        "500":
          $ref: ./common/responses.yaml#/components/responses/InternalServerError
        "200":
          description: Updated document
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Document"
        "403":
          $ref: ./common/responses.yaml#/components/responses/Forbidden
  /orgs/{orgId}/documents/{documentId}/signatures:
    post:
      tags:
        - ESignatures
      summary: Request e-signature for a document
      operationId: requestESignature
      security:
        - oauth2:
            - write:documents
        - apiKey: []
      parameters:
        - $ref: ./common/components.yaml#/components/parameters/orgId
        - $ref: ./common/components.yaml#/components/parameters/orgIdHeader
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - signers
              properties:
                signers:
                  type: array
                  items:
                    type: object
                    required:
                      - email
                    properties:
                      name:
                        type: string
                      email:
                        type: string
                        format: email
                      role:
                        type: string
                        enum:
                          - SIGNER
                          - CC
                          - REVIEWER
                method:
                  type: string
                  enum:
                    - DOCUSIGN
                    - UAE_PASS
                    - MANUAL
                    - QUUB_NATIVE
                dueDate:
                  type: string
                  format: date-time
      responses:
        "400":
          $ref: ./common/responses.yaml#/components/responses/BadRequest
        "401":
          $ref: ./common/responses.yaml#/components/responses/Unauthorized
        "409":
          $ref: ./common/responses.yaml#/components/responses/Conflict
        "422":
          $ref: ./common/responses.yaml#/components/responses/ValidationError
        "500":
          $ref: ./common/responses.yaml#/components/responses/InternalServerError
        "201":
          description: E-signature request created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/SignatureRequest"
        "403":
          $ref: ./common/responses.yaml#/components/responses/Forbidden
  /orgs/{orgId}/documents/{documentId}/signatures/{signatureId}:
    get:
      tags:
        - ESignatures
      summary: Get e-signature request status
      operationId: getSignatureStatus
      security:
        - oauth2:
            - read:documents
        - apiKey: []
      parameters:
        - $ref: ./common/components.yaml#/components/parameters/orgId
        - $ref: ./common/components.yaml#/components/parameters/orgIdHeader
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: signatureId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "400":
          $ref: ./common/responses.yaml#/components/responses/BadRequest
        "401":
          $ref: ./common/responses.yaml#/components/responses/Unauthorized
        "500":
          $ref: ./common/responses.yaml#/components/responses/InternalServerError
        "200":
          description: E-signature request status
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/SignatureRequest"
        "403":
          $ref: ./common/responses.yaml#/components/responses/Forbidden
  /orgs/{orgId}/publications:
    get:
      tags:
        - Publications
      summary: List published documents
      operationId: listPublications
      security:
        - oauth2:
            - read:documents
        - apiKey: []
      parameters:
        - $ref: ./common/components.yaml#/components/parameters/orgId
        - $ref: ./common/components.yaml#/components/parameters/orgIdHeader
        - $ref: ./common/pagination.yaml#/components/parameters/cursor
        - $ref: ./common/pagination.yaml#/components/parameters/limit
      responses:
        "400":
          $ref: ./common/responses.yaml#/components/responses/BadRequest
        "401":
          $ref: ./common/responses.yaml#/components/responses/Unauthorized
        "403":
          $ref: ./common/responses.yaml#/components/responses/Forbidden
        "404":
          $ref: ./common/responses.yaml#/components/responses/NotFound
        "429":
          $ref: ./common/responses.yaml#/components/responses/TooManyRequests
        "500":
          $ref: ./common/responses.yaml#/components/responses/InternalServerError
        "200":
          description: List of published documents
          content:
            application/json:
              schema:
                allOf:
                  - $ref: ./common/pagination.yaml#/components/schemas/PageResponse
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/Publication"
components:
  securitySchemes:
    bearerAuth:
      $ref: ./common/components.yaml#/components/securitySchemes/bearerAuth
    oauth2:
      $ref: ./common/components.yaml#/components/securitySchemes/oauth2
    apiKey:
      $ref: ./common/components.yaml#/components/securitySchemes/apiKey
  schemas:
    Document:
      type: object
      description: Represents an uploaded document within an organization.
      properties:
        id:
          type: string
          format: uuid
        orgId:
          type: string
          format: uuid
        name:
          type: string
        type:
          type: string
          enum:
            - PDF
            - DOCX
            - IMAGE
            - XLSX
            - JSON
        status:
          type: string
          enum:
            - DRAFT
            - REVIEW
            - PUBLISHED
            - ARCHIVED
        tags:
          type: array
          items:
            type: string
        storageUrl:
          type: string
          format: uri
        linkedProjectId:
          oneOf:
            - type: string
              format: uuid
            - type: "null"
        createdBy:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    SignatureRequest:
      type: object
      description: Electronic signature request metadata.
      properties:
        id:
          type: string
          format: uuid
        documentId:
          type: string
          format: uuid
        method:
          type: string
          enum:
            - DOCUSIGN
            - UAE_PASS
            - MANUAL
            - QUUB_NATIVE
        status:
          type: string
          enum:
            - PENDING
            - COMPLETED
            - REJECTED
            - EXPIRED
        signers:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              email:
                type: string
                format: email
              role:
                type: string
                enum:
                  - SIGNER
                  - CC
                  - REVIEWER
              status:
                type: string
                enum:
                  - PENDING
                  - SIGNED
                  - DECLINED
        requestedAt:
          type: string
          format: date-time
        completedAt:
          oneOf:
            - type: string
              format: date-time
            - type: "null"
    Publication:
      type: object
      description: Metadata for a published document.
      properties:
        id:
          type: string
          format: uuid
        orgId:
          type: string
          format: uuid
        documentId:
          type: string
          format: uuid
        title:
          type: string
        category:
          type: string
          enum:
            - REPORT
            - DISCLOSURE
            - NOTICE
            - CONTRACT
        publishedAt:
          type: string
          format: date-time
        publishedBy:
          type: string
          format: uuid
        audience:
          type: string
          enum:
            - PUBLIC
            - INVESTORS
            - INTERNAL
        documentUrl:
          type: string
          format: uri
