openapi: 3.0.3
info:
  title: QuantumHR B2B API
  description: API для интеграции с платформой QuantumHR (исполнители, выплаты, документы, 1С)
  version: 1.0.0

servers:
  - url: /api/v1
    description: API v1

security:
  - bearerAuth: []

paths:
  /health:
    get:
      summary: Проверка доступности API
      operationId: getHealth
      tags: [Health]
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok

  /company:
    get:
      summary: Получить данные компании
      operationId: getCompany
      tags: [Company]
      responses:
        '200':
          description: Данные компании
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Company'
        '404':
          $ref: '#/components/responses/NotFound'

  /executors:
    get:
      summary: Список исполнителей
      operationId: listExecutors
      tags: [Executors]
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: Пагинированный список исполнителей
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExecutorPaginated'
    post:
      summary: Создать исполнителя
      operationId: createExecutor
      tags: [Executors]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExecutorCreate'
      responses:
        '201':
          description: Исполнитель создан
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Executor'
        '422':
          $ref: '#/components/responses/ValidationError'

  /executors/{id}:
    get:
      summary: Получить исполнителя по ID
      operationId: getExecutor
      tags: [Executors]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          description: Данные исполнителя
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Executor'
        '404':
          $ref: '#/components/responses/NotFound'

  /npd/check:
    post:
      summary: Проверка статуса НПД
      operationId: checkNpd
      tags: [NPD]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [executor_id, inn]
              properties:
                executor_id:
                  type: string
                  format: uuid
                  description: ID исполнителя
                inn:
                  type: string
                  minLength: 12
                  maxLength: 12
                  description: ИНН физлица
      responses:
        '200':
          description: Результат проверки НПД
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NpdCheck'
        '422':
          $ref: '#/components/responses/ValidationError'

  /payouts:
    get:
      summary: Список выплат
      operationId: listPayouts
      tags: [Payouts]
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: Пагинированный список выплат
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayoutPaginated'
    post:
      summary: Создать выплату
      operationId: createPayout
      tags: [Payouts]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PayoutCreate'
      responses:
        '201':
          description: Выплата создана
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payout'
        '422':
          $ref: '#/components/responses/ValidationError'

  /payouts/batch:
    post:
      summary: Массовое создание выплат из CSV
      operationId: createBatchPayouts
      tags: [Payouts]
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file:
                  type: string
                  format: binary
                  description: CSV файл (разделитель ;), колонки phone, amount, currency?, description?
      responses:
        '201':
          description: Выплаты созданы
          content:
            application/json:
              schema:
                type: object
                properties:
                  created:
                    type: integer
                  payout_ids:
                    type: array
                    items:
                      type: string
                      format: uuid
        '422':
          description: Ошибки валидации строк
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  row_errors:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string

  /payouts/{id}:
    get:
      summary: Получить выплату по ID
      operationId: getPayout
      tags: [Payouts]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          description: Данные выплаты
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payout'
        '404':
          $ref: '#/components/responses/NotFound'

  /documents:
    get:
      summary: Список документов
      operationId: listDocuments
      tags: [Documents]
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: Пагинированный список документов
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentPaginated'

  /documents/{id}:
    get:
      summary: Получить документ по ID
      operationId: getDocument
      tags: [Documents]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          description: Данные документа
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Document'
        '404':
          $ref: '#/components/responses/NotFound'

  /webhooks:
    get:
      summary: Список webhook-эндпоинтов
      operationId: listWebhooks
      tags: [Webhooks]
      responses:
        '200':
          description: Список webhook-эндпоинтов
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/WebhookEndpoint'
    post:
      summary: Создать webhook-эндпоинт
      operationId: createWebhook
      tags: [Webhooks]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url, events]
              properties:
                url:
                  type: string
                  format: uri
                  maxLength: 500
                events:
                  type: array
                  minItems: 1
                  items:
                    type: string
      responses:
        '201':
          description: Webhook создан (secret возвращается только при создании)
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  url:
                    type: string
                    format: uri
                  events:
                    type: array
                    items:
                      type: string
                  secret:
                    type: string
                    description: Секрет для подписи HMAC (сохраните, повторно не показывается)
        '422':
          $ref: '#/components/responses/ValidationError'

  /webhooks/{id}:
    delete:
      summary: Деактивировать webhook-эндпоинт
      operationId: deleteWebhook
      tags: [Webhooks]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          description: Webhook деактивирован
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    example: true
        '404':
          $ref: '#/components/responses/NotFound'

  /1c/import:
    post:
      summary: Импорт из 1С (исполнители или выплаты)
      operationId: oneCImport
      tags: [1C Integration]
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [type, file]
              properties:
                type:
                  type: string
                  enum: [executors, payouts]
                file:
                  type: string
                  format: binary
                  description: CSV/TXT/XML файл (для executors — phone, first_name, last_name, middle_name, inn; для payouts — как в batch)
      responses:
        '200':
          description: Результат импорта
          content:
            application/json:
              schema:
                oneOf:
                  - type: object
                    properties:
                      imported:
                        type: integer
                      errors:
                        type: array
                        items:
                          type: string
                  - type: object
                    properties:
                      created:
                        type: integer
                      errors:
                        type: object
                        additionalProperties:
                          type: array
                          items:
                            type: string
        '422':
          $ref: '#/components/responses/ValidationError'

  /webhooks/quantum-payouts:
    post:
      summary: Callback от Quantum Payouts (публичный, без Bearer)
      operationId: quantumPayoutsWebhook
      tags: [Webhooks]
      security: []
      parameters:
        - name: X-Signature
          in: header
          required: true
          schema:
            type: string
          description: HMAC-SHA256 подпись тела запроса
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [event, payment_id, status]
              properties:
                event:
                  type: string
                payment_id:
                  type: string
                status:
                  type: string
                  enum: [succeeded, failed, reversed]
      responses:
        '200':
          description: Callback обработан
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    example: true
        '403':
          description: Неверная подпись
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Выплата не найдена
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /1c/export:
    get:
      summary: Экспорт в 1С (исполнители или выплаты)
      operationId: oneCExport
      tags: [1C Integration]
      parameters:
        - name: type
          in: query
          required: true
          schema:
            type: string
            enum: [executors, payouts]
        - name: date_from
          in: query
          schema:
            type: string
            format: date
        - name: date_to
          in: query
          schema:
            type: string
            format: date
        - name: format
          in: query
          schema:
            type: string
            enum: [json, csv]
            default: json
      responses:
        '200':
          description: JSON или CSV-файл
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ExecutorExport'
            text/csv:
              schema:
                type: string
                format: binary

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Sanctum token

  parameters:
    Page:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1
    PerPage:
      name: per_page
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    UuidId:
      name: id
      in: path
      required: true
      schema:
        type: string
        format: uuid

  responses:
    NotFound:
      description: Ресурс не найден
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ValidationError:
      description: Ошибка валидации
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'

  schemas:
    Company:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        inn:
          type: string
        kpp:
          type: string
        ogrn:
          type: string
        legal_address:
          type: string
        contact_name:
          type: string
        contact_email:
          type: string
        contact_phone:
          type: string
        industry_segment:
          type: string
        status:
          type: string
          enum: [pending_kyc, active, suspended, deactivated]
        ip_allowlist:
          type: array
          items:
            type: string
        settings:
          type: object
        uat_provisioned_at:
          type: string
          format: date-time
        activated_at:
          type: string
          format: date-time

    Executor:
      type: object
      properties:
        id:
          type: string
          format: uuid
        first_name:
          type: string
        last_name:
          type: string
        middle_name:
          type: string
        inn:
          type: string
        email:
          type: string
        onboarding_status:
          type: string
          enum: [invited, started, profile_filled, identity_verified, npd_verified, documents_signed, payout_method_added, active, on_hold, suspended, deactivated, rejected]
        npd_status:
          type: string
          enum: [unknown, confirmed, not_confirmed, check_failed]
        npd_last_checked_at:
          type: string
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    ExecutorCreate:
      type: object
      required: [phone, password, first_name, last_name, inn]
      properties:
        phone:
          type: string
          maxLength: 20
        password:
          type: string
          minLength: 8
        first_name:
          type: string
          maxLength: 100
        last_name:
          type: string
          maxLength: 100
        middle_name:
          type: string
          maxLength: 100
        inn:
          type: string
          minLength: 12
          maxLength: 12
        email:
          type: string
          format: email
        birth_date:
          type: string
          format: date

    ExecutorExport:
      type: object
      properties:
        id:
          type: string
          format: uuid
        full_name:
          type: string
        inn:
          type: string
        onboarding_status:
          type: string
        npd_status:
          type: string

    ExecutorPaginated:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Executor'
        meta:
          $ref: '#/components/schemas/PaginationMeta'

    Payout:
      type: object
      properties:
        id:
          type: string
          format: uuid
        executor_id:
          type: string
          format: uuid
        idempotency_key:
          type: string
        amount:
          type: number
          format: decimal
        currency:
          type: string
          example: RUB
        status:
          type: string
          enum: [draft, validated, npd_checked, approved, processing, succeeded, failed, reversed, manual_review, blocked]
        error_category:
          type: string
        error_message:
          type: string
        provider_payment_id:
          type: string
        sent_to_provider_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
        created_at:
          type: string
          format: date-time
        executor:
          $ref: '#/components/schemas/Executor'

    PayoutCreate:
      type: object
      required: [executor_id, idempotency_key, amount]
      properties:
        executor_id:
          type: string
          format: uuid
        idempotency_key:
          type: string
          maxLength: 64
        amount:
          type: number
          minimum: 0.01
          maximum: 999999999.99
        currency:
          type: string
          maxLength: 3
          default: RUB
        description:
          type: string
          maxLength: 1000
        legal_basis_ref:
          type: string
          maxLength: 255
        beneficiary_ref:
          type: string
          maxLength: 255

    PayoutPaginated:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Payout'
        meta:
          $ref: '#/components/schemas/PaginationMeta'

    Document:
      type: object
      properties:
        id:
          type: string
          format: uuid
        company_id:
          type: string
          format: uuid
        executor_id:
          type: string
          format: uuid
        template_id:
          type: string
        document_type:
          type: string
          enum: [framework_contract, completion_act, pep_consent, supplementary_agreement, task_specification, dispute_protocol, suspension_notice]
        status:
          type: string
          enum: [draft, generated, sent_for_signing, signed, rejected, revoked]
        variables:
          type: object
        document_hash:
          type: string
        storage_path:
          type: string
        signed_at:
          type: string
          format: date-time
        signatures:
          type: array

    DocumentPaginated:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Document'
        meta:
          $ref: '#/components/schemas/PaginationMeta'

    WebhookEndpoint:
      type: object
      properties:
        id:
          type: string
          format: uuid
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        is_active:
          type: boolean

    NpdCheck:
      type: object
      properties:
        id:
          type: string
          format: uuid
        executor_id:
          type: string
          format: uuid
        inn:
          type: string
        request_date:
          type: string
          format: date
        result:
          type: string
        decision:
          type: string
        decision_reason:
          type: string
        response_time_ms:
          type: integer
        created_at:
          type: string
          format: date-time

    PaginationMeta:
      type: object
      properties:
        current_page:
          type: integer
        last_page:
          type: integer
        per_page:
          type: integer
        total:
          type: integer

    Error:
      type: object
      properties:
        message:
          type: string
        error:
          type: string

    ValidationError:
      type: object
      properties:
        message:
          type: string
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
