openapi: 3.1.0
info:
  title: IAM
  description: '# Sistema de Gestión de Identidad y Acceso (IAM) - Transcend


    Este API es parte del sistema **Transcend** y corresponde al módulo de Identity
    and Access Management (IAM).

    Proporciona endpoints completos para la gestión de usuarios, autenticación, empresas
    y API keys.


    ## Funcionalidades principales:


    ### 1. Autenticación y Gestión de Usuarios

    - Registro de nuevos usuarios con creación automática de empresa

    - Login con JWT tokens

    - Recuperación y reset de contraseñas

    - Gestión de perfiles de usuario

    - Validación y renovación de tokens


    ### 2. Gestión de Empresas

    - Creación y actualización de información de empresa

    - Gestión de usuarios dentro de la empresa

    - Configuración de webhooks para notificaciones


    ### 3. Gestión de API Keys

    - Generación de API keys para integraciones

    - Verificación de API keys desde otros sistemas

    - Activación/desactivación de API keys


    ## Flujos típicos de uso:


    ### Para usuarios nuevos:

    1. Registro en `/api/auth/register` con datos de empresa

    2. Login en `/api/auth/login` para obtener token JWT

    3. Configurar empresa en `/api/company/`

    4. Crear API key en `/api/apikeys/` para integraciones


    ### Para integraciones externas:

    1. Autenticación con API key en header `x-api-key`

    2. Verificación de API key en `/api/apikeys/verify`

    3. Uso de endpoints protegidos según permisos

    '
  version: 1.0.0
  contact:
    email: support@cargoffer.com
  license:
    name: Private API - Access by agreement only
servers:
- url: https://api.pro.cargoffer.com
  description: Producción
tags:
- name: Authentication
  description: Endpoints para autenticación de usuarios, registro, login y gestión
    de tokens
- name: Company
  description: Gestión de empresas, usuarios de empresa y configuración
- name: API Keys
  description: Generación, verificación y gestión de API keys para integraciones
- name: Health
  description: Endpoints de monitoreo y verificación del estado del servicio
- name: Legacy
  description: Endpoints legacy mantenidos por compatibilidad
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Token JWT obtenido del endpoint de login o registro
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: API key para autenticación de servidor a servidor
  schemas:
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: Mensaje descriptivo del error
        message:
          type: string
          description: Detalles adicionales del error
    SuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Indica si la operación fue exitosa
        message:
          type: string
          description: Mensaje descriptivo del resultado
    LoginRequest:
      type: object
      required:
      - email
      - password
      properties:
        email:
          type: string
          format: email
          description: Email del usuario registrado
        password:
          type: string
          description: Contraseña del usuario (mínimo 6 caracteres)
    LoginResponse:
      type: object
      properties:
        token:
          type: string
          description: Token JWT para autenticación
        user:
          type: object
          description: Información básica del usuario
    RegisterRequest:
      type: object
      required:
      - email
      - password
      - company_cif
      properties:
        email:
          type: string
          format: email
          description: Email para el nuevo usuario
        password:
          type: string
          description: Contraseña (mínimo 6 caracteres)
        company_cif:
          type: string
          description: CIF/NIF de la empresa (requerido)
    TokenResponse:
      type: object
      properties:
        token:
          type: string
          description: Token JWT firmado para autenticación
        expiresIn:
          type: integer
          format: int64
          description: Timestamp UNIX de expiración
    HealthResponse:
      type: object
      properties:
        status:
          type: string
          description: Estado del servicio
        dbStatus:
          type: string
          description: Estado de la conexión a la base de datos
  responses:
    Unauthorized:
      description: Token JWT inválido, expirado o faltante
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Permisos insuficientes para la operación
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    BadRequest:
      description: Datos inválidos o faltantes
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalServerError:
      description: Error interno del servidor
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    LoginSuccess:
      description: Login exitoso con token JWT
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/LoginResponse'
paths:
  /health:
    get:
      tags:
      - Health
      summary: Verificar estado del servicio
      description: Endpoint para verificar que el servicio está funcionando correctamente
      responses:
        '200':
          description: Servicio funcionando correctamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /test:
    get:
      tags:
      - Health
      summary: Endpoint de prueba
      description: Alias de /health para compatibilidad
      responses:
        '200':
          description: Servicio funcionando correctamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/login:
    post:
      tags:
      - Authentication
      summary: Iniciar sesión de usuario
      description: Autentica un usuario con email y contraseña, retorna token JWT
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
      responses:
        '200':
          $ref: '#/components/responses/LoginSuccess'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          description: Credenciales inválidas
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Demasiadas solicitudes - Rate limit excedido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/register:
    post:
      tags:
      - Authentication
      summary: Registrar nuevo usuario y empresa
      description: Crea un nuevo usuario y empresa asociada
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterRequest'
      responses:
        '200':
          description: Registro exitoso
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '400':
          description: Datos inválidos o duplicados
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Demasiados registros
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/me:
    get:
      tags:
      - Authentication
      summary: Obtener información del usuario actual
      description: Retorna información del usuario autenticado
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Información del usuario obtenida
          content:
            application/json:
              schema:
                type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/profile:
    put:
      tags:
      - Authentication
      summary: Actualizar perfil de usuario
      description: Actualiza información del usuario autenticado
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Perfil actualizado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/validate-token:
    get:
      tags:
      - Authentication
      summary: Validar token JWT
      description: Verifica si un token JWT es válido
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Token válido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/renew-token:
    post:
      tags:
      - Authentication
      summary: Renovar token JWT
      description: Renueva un token JWT válido
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Token renovado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/recovery:
    post:
      tags:
      - Authentication
      summary: Solicitar recuperación de contraseña
      description: Inicia proceso de recuperación de contraseña
      responses:
        '200':
          description: Email de recuperación enviado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/subscription:
    post:
      tags:
      - Authentication
      summary: Actualizar suscripción de usuario
      description: Actualiza el tipo de suscripción del usuario autenticado
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      responses:
        '200':
          description: Suscripción actualizada exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/check-internal-token:
    post:
      tags:
      - Authentication
      summary: Verificar token interno
      description: Verifica un token interno del sistema
      responses:
        '200':
          description: Token interno válido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/auth/verify-service-token:
    post:
      tags:
      - Authentication
      summary: Verificar token de servicio
      description: Verifica un token de servicio
      responses:
        '200':
          description: Token de servicio válido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/company/me:
    get:
      tags:
      - Company
      summary: Obtener información de la empresa
      description: Retorna información de la empresa del usuario autenticado
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Información de empresa obtenida
          content:
            application/json:
              schema:
                type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/company:
    post:
      tags:
      - Company
      summary: Crear nueva empresa
      description: Crea una nueva empresa
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Empresa creada exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
    put:
      tags:
      - Company
      summary: Actualizar empresa
      description: Actualiza información de la empresa
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Empresa actualizada exitosamente
          content:
            application/json:
              schema:
                type: object
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/company/webhook:
    put:
      tags:
      - Company
      summary: Actualizar webhook de empresa
      description: Configura URL de webhook para notificaciones
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Webhook actualizado exitosamente
          content:
            application/json:
              schema:
                type: object
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/company/users:
    get:
      tags:
      - Company
      summary: Listar usuarios de la empresa
      description: Retorna lista de usuarios de la empresa
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Lista de usuarios obtenida
          content:
            application/json:
              schema:
                type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
    post:
      tags:
      - Company
      summary: Crear usuario en la empresa
      description: Crea un nuevo usuario en la empresa
      security:
      - BearerAuth: []
      responses:
        '201':
          description: Usuario creado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/company/users/{userId}:
    put:
      tags:
      - Company
      summary: Actualizar usuario de la empresa
      description: Actualiza información de un usuario específico de la empresa
      parameters:
      - name: userId
        in: path
        required: true
        schema:
          type: string
        description: ID del usuario a actualizar
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Usuario actualizado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      tags:
      - Company
      summary: Eliminar usuario de la empresa
      description: Elimina un usuario específico de la empresa
      parameters:
      - name: userId
        in: path
        required: true
        schema:
          type: string
        description: ID del usuario a eliminar
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Usuario eliminado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/apikeys:
    post:
      tags:
      - API Keys
      summary: Crear nueva API key
      description: Genera una nueva API key para el usuario
      security:
      - BearerAuth: []
      responses:
        '200':
          description: API key creada exitosamente
          content:
            application/json:
              schema:
                type: object
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
    get:
      tags:
      - API Keys
      summary: Obtener mi API key
      description: Retorna información de la API key del usuario
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Información de API key obtenida
          content:
            application/json:
              schema:
                type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      tags:
      - API Keys
      summary: Eliminar mi API key
      description: Elimina la API key del usuario
      security:
      - BearerAuth: []
      responses:
        '200':
          description: API key eliminada exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/apikeys/verify:
    post:
      tags:
      - API Keys
      summary: Verificar API key
      description: Verifica si una API key es válida
      security:
      - ApiKeyAuth: []
      responses:
        '200':
          description: API key válida
          content:
            application/json:
              schema:
                type: object
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          description: API key inválida
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /token:
    get:
      tags:
      - Legacy
      summary: Obtener token JWT (legacy)
      description: '**⚠️ DEPRECATED:** Use `/api/auth/login` instead.

        Endpoint legacy para obtener token JWT.

        '
      deprecated: true
      responses:
        '200':
          description: Token obtenido exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/token/validate-token:
    get:
      tags:
      - Legacy
      summary: Validar token JWT (legacy)
      description: '**⚠️ DEPRECATED:** Use `/api/auth/validate-token` instead.

        Alias para validar token JWT.

        '
      deprecated: true
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Token válido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/token/renew-token:
    post:
      tags:
      - Legacy
      summary: Renovar token JWT (legacy)
      description: '**⚠️ DEPRECATED:** Use `/api/auth/renew-token` instead.

        Alias para renovar token JWT.

        '
      deprecated: true
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Token renovado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'
