openapi: 3.0.4
info:
  title: Evolution Foundation - CRM Service - Products
  description: |
    Product catalog management with variants, agent attach, and pipeline sales tracking.

    Available starting `v1.0.0-rc3`.

    **Note:** This OpenAPI spec was generated from the controller as part of the rc3 release. Schemas reflect the controller surface but request/response examples may need refinement based on real payloads.
  version: 1.0.0
servers:
- url: https://api.evoai.app
  description: Production server
- url: http://localhost:3000
  description: Development server
- url: '{customUrl}'
  description: Custom server
  variables:
    customUrl:
      default: https://your-instance.com
      description: Enter your server URL
paths:
  /api/v1/products:
    get:
      operationId: list-products
      summary: List Products
      description: Lists all products in the account catalog. Requires `products.read`.
      security:
      - userApiKey: []
      parameters:
      - name: page
        in: query
        schema:
          type: integer
          default: 1
      - name: per_page
        in: query
        schema:
          type: integer
          default: 25
      - name: status
        in: query
        description: Filter by status (`active` or `inactive`)
        schema:
          type: string
          enum: [active, inactive]
      - name: q
        in: query
        description: Search by name or SKU
        schema:
          type: string
      responses:
        '200':
          description: Products retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductListResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: create-product
      summary: Create Product
      description: Creates a new product in the catalog. Requires `products.create`.
      security:
      - userApiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [product]
              properties:
                product:
                  $ref: '#/components/schemas/ProductInput'
                labels:
                  type: array
                  items: { type: string }
                  description: Optional list of label slugs to attach
      responses:
        '201':
          description: Product created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductResponse'
        '422':
          $ref: '#/components/responses/ValidationError'

  /api/v1/products/{id}:
    parameters:
    - name: id
      in: path
      required: true
      schema: { type: string, format: uuid }
    get:
      operationId: get-product
      summary: Get Product
      description: Retrieves a single product by id. Requires `products.read`.
      security:
      - userApiKey: []
      responses:
        '200':
          description: Product retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductResponse'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: update-product
      summary: Update Product
      description: Updates fields of an existing product. Requires `products.update`.
      security:
      - userApiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                product:
                  $ref: '#/components/schemas/ProductInput'
      responses:
        '200':
          description: Product updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductResponse'
        '422':
          $ref: '#/components/responses/ValidationError'
    delete:
      operationId: delete-product
      summary: Delete Product
      description: |
        Deletes a product. Requires `products.delete`.

        Returns 422 if the product is in use (referenced by pipeline items or active variants).
      security:
      - userApiKey: []
      responses:
        '200':
          description: Product deleted successfully
        '422':
          description: Product is in use and cannot be deleted

components:
  securitySchemes:
    userApiKey:
      type: apiKey
      in: header
      name: api_access_token
  schemas:
    ProductInput:
      type: object
      properties:
        name: { type: string, example: "Plano Pro" }
        slug: { type: string, example: "plano-pro" }
        kind: { type: string, example: "subscription" }
        description: { type: string }
        sku: { type: string }
        default_price: { type: number, format: float, example: 199.90 }
        currency: { type: string, example: "BRL" }
        purchase_url: { type: string, format: uri }
        status: { type: string, enum: [active, inactive] }
        stock_quantity: { type: integer }
        metadata: { type: object, additionalProperties: true }
        variants_attributes:
          type: array
          items:
            type: object
            properties:
              id: { type: string, format: uuid }
              _destroy: { type: boolean }
              name: { type: string }
              sku: { type: string }
              price_override: { type: number, format: float }
              stock_quantity: { type: integer }
              position: { type: integer }
              attributes_data: { type: object, additionalProperties: true }
    Product:
      type: object
      properties:
        id: { type: string, format: uuid }
        name: { type: string }
        slug: { type: string }
        kind: { type: string }
        description: { type: string }
        sku: { type: string }
        default_price: { type: number, format: float }
        currency: { type: string }
        status: { type: string, enum: [active, inactive] }
        stock_quantity: { type: integer }
        metadata: { type: object, additionalProperties: true }
        labels:
          type: array
          items: { type: string }
        variants:
          type: array
          items:
            $ref: '#/components/schemas/Variant'
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    Variant:
      type: object
      properties:
        id: { type: string, format: uuid }
        name: { type: string }
        sku: { type: string }
        price_override: { type: number, format: float }
        stock_quantity: { type: integer }
        position: { type: integer }
        attributes_data: { type: object, additionalProperties: true }
    ProductResponse:
      type: object
      required: [success, data, meta, message]
      properties:
        success: { type: boolean, example: true }
        data: { $ref: '#/components/schemas/Product' }
        meta:
          type: object
          properties:
            timestamp: { type: string, format: date-time }
        message: { type: string }
    ProductListResponse:
      type: object
      required: [success, data, meta, message]
      properties:
        success: { type: boolean, example: true }
        data:
          type: array
          items: { $ref: '#/components/schemas/Product' }
        meta:
          type: object
          properties:
            timestamp: { type: string, format: date-time }
            pagination:
              type: object
              properties:
                current_page: { type: integer }
                total_pages: { type: integer }
                total_count: { type: integer }
        message: { type: string }
  responses:
    Unauthorized:
      description: Missing or invalid authentication
      content:
        application/json:
          schema:
            type: object
            properties:
              success: { type: boolean, example: false }
              message: { type: string, example: "Unauthorized" }
    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            type: object
            properties:
              success: { type: boolean, example: false }
              message: { type: string, example: "Forbidden" }
    NotFound:
      description: Product not found
      content:
        application/json:
          schema:
            type: object
            properties:
              success: { type: boolean, example: false }
              message: { type: string, example: "Not Found" }
    ValidationError:
      description: Validation failed
      content:
        application/json:
          schema:
            type: object
            properties:
              success: { type: boolean, example: false }
              message: { type: string }
              details:
                type: array
                items: { type: string }
