openapi: 3.0.3
info:
  title: Traceable API
  description: |
    API REST para integração de ERP, WMS e TMS — entregas, ocorrências, cotação de frete,
    CT-e, frota e notificações por webhook.

    ## Autenticação
    Obtenha um JWT em `POST /api/auth` e envie `Authorization: Bearer {token}` nas requisições.
    O login retorna as empresas vinculadas com **nome**, **CNPJ** (`document`) e permissões — o **ID interno da empresa não é exposto**.
    Use o CNPJ retornado em `companies[].document` no header `Company-Cnpj` em todas as demais requisições.

    ## Webhooks
    Cadastre URLs de notificação em `/api/webhooks` (eventos: `DeliveryCreated`, `OccurrenceCreated`, `AuditCreated`, `AuditScore`).

    ## Ocorrências
    No campo `occurrence_type_id`, envie o **código do tipo de ocorrência** configurado na sua empresa
    (ex.: `ENTREGUE`, `EM_TRANSITO`). Esse código é o que você define ao cadastrar o tipo no Traceable — não use
    o número sequencial exibido apenas na interface web do Traceable.

    **Geolocalização (opcional):** `latitude` e `longitude` são recomendadas (WGS84, decimal com ponto).
    Se enviadas, devem ser válidas; vazias ou omitidas são aceitas. Valores inválidos retornam HTTP 400.
  version: 2.4.4
  contact:
    name: Traceable
    url: https://traceable.com

servers:
  - url: /
    description: Use ao testar os endpoints nesta página de documentação
  - url: https://traceablelog.com
    description: Produção Traceable

tags:
  - name: Autenticacao
    description: Autenticação — login e contexto de acesso
  - name: Entregas
    description: Criação e importação de entregas
  - name: Ocorrencias
    description: Ocorrências — atualização de status e comprovantes (POD)
  - name: Frete
    description: Cotação e auditoria de CT-e
  - name: Frota
    description: Geolocalização de veículos
  - name: Webhooks
    description: Cadastro de URLs de notificação por evento

paths:
  /api/auth:
    post:
      tags: [Autenticacao]
      summary: Autenticar usuário
      description: |
        Retorna token de acesso, dados do usuário, empresas vinculadas e permissões por empresa.
        Cada item em `data.companies` traz `name`, `document` (CNPJ), `role` e `permissions` — **sem `id` interno**.
        Informe o CNPJ de `document` no header `Company-Cnpj` nas próximas chamadas.
      operationId: authLogin
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthRequest'
            example:
              email: integracao@empresa.com.br
              password: "********"
      responses:
        '200':
          description: Autenticação realizada
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/AuthResponseData'
              example:
                status: 200
                message: Autenticação realizada com sucesso.
                data:
                  token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
                  expires_in: 300
                  expires_at: "2026-05-26T14:30:00-03:00"
                  user:
                    id: 42
                    username: integracao
                    email: integracao@empresa.com.br
                    type: internal
                    transporter_id: null
                    customer_id: null
                  companies:
                    - name: EMPRESA EXEMPLO LTDA
                      document: "12345678000199"
                      logo: null
                      is_default: true
                      role: company_admin
                      role_name: Administrador
                      permissions: ["delivery_create", "occurrence_insert", "*"]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /api/create_delivery:
    post:
      tags: [Entregas]
      summary: Criar entrega (JSON)
      description: |
        Cria entrega com cliente, endereço e notas fiscais opcionais.
        Configuração de operação, direção e transportadora via headers.
      operationId: createDelivery
      parameters:
        - $ref: '#/components/parameters/CompanyCnpj'
        - $ref: '#/components/parameters/OperationId'
        - $ref: '#/components/parameters/Direction'
        - $ref: '#/components/parameters/TransporterCnpj'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDeliveryRequest'
      responses:
        '201':
          description: Entrega criada
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/CreateDeliveryResponseData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/create_delivery_xml:
    post:
      tags: [Entregas]
      summary: Criar entrega a partir de XML (NF-e)
      description: Importa arquivo XML de NF-e e cria a entrega automaticamente.
      operationId: createDeliveryXml
      parameters:
        - $ref: '#/components/parameters/CompanyCnpj'
        - $ref: '#/components/parameters/OperationId'
        - $ref: '#/components/parameters/Direction'
        - $ref: '#/components/parameters/TransporterCnpj'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/CreateDeliveryXmlRequest'
      responses:
        '201':
          description: Entrega criada via XML
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/CreateDeliveryXmlResponseData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /api/create_occurrence:
    post:
      tags: [Ocorrencias]
      summary: Registrar ocorrência
      description: |
        Atualiza o status da entrega.

        **Geolocalização:** `latitude` e `longitude` opcionais (recomendadas).

        **Tipos finais (POD):** exige `receiver_name`, `receiver_document` e
        `proof_image` (JPG/PNG, máx. 5 MB).

        Identifique a entrega por `delivery_id`, `tracking_code` ou `invoice_key`.
      operationId: createOccurrence
      parameters:
        - $ref: '#/components/parameters/CompanyCnpj'
        - $ref: '#/components/parameters/TransporterCnpj'
        - name: X-App-Version
          in: header
          schema:
            type: string
          description: Versão do aplicativo ou integração (opcional, para rastreabilidade)
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/CreateOccurrenceRequest'
      responses:
        '201':
          description: Ocorrência registrada
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/CreateOccurrenceResponseData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/import_cte:
    post:
      tags: [Frete]
      summary: Importar CT-e (XML)
      description: Processa XML de Conhecimento de Transporte Eletrônico para auditoria de frete.
      operationId: importCte
      parameters:
        - $ref: '#/components/parameters/CompanyCnpjDigits'
        - $ref: '#/components/parameters/TransporterCnpjDigits'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/ImportCteRequest'
      responses:
        '201':
          description: CT-e processado
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/ImportCteResponseData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/freight_quote:
    post:
      tags: [Frete]
      summary: Cotar frete
      description: Calcula cotações com base nas regras de frete, regiões e prazos (SLA) configurados na empresa.
      operationId: freightQuote
      parameters:
        - $ref: '#/components/parameters/CompanyCnpj'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FreightQuoteRequest'
      responses:
        '200':
          description: Cotação realizada
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/FreightQuoteResponseData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/fleet_geolocation:
    post:
      tags: [Frota]
      summary: Atualizar geolocalização da frota
      description: |
        Atualização em lote da última posição GPS dos veículos.
        Headers obrigatórios: `Company-Cnpj` e `Transporter-Cnpj`.
        Contas de transportadora usam o CNPJ vinculado ao token; demais integrações devem enviar `Transporter-Cnpj`.
      operationId: fleetGeolocation
      parameters:
        - $ref: '#/components/parameters/CompanyCnpj'
        - $ref: '#/components/parameters/TransporterCnpjRequired'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FleetGeolocationRequest'
      responses:
        '200':
          description: Processamento concluído
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/FleetGeolocationResponseData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/webhooks:
    get:
      tags: [Webhooks]
      summary: Listar webhooks
      operationId: listWebhooks
      parameters:
        - $ref: '#/components/parameters/CompanyCnpjDigits'
      responses:
        '200':
          description: Lista de endpoints
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/WebhookEndpoint'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      tags: [Webhooks]
      summary: Cadastrar webhook
      description: |
        Registra a URL que receberá notificações.

        **Eventos:** `DeliveryCreated`, `OccurrenceCreated`, `AuditCreated`, `AuditScore`.

        Após criar, guarde o `secret` da resposta. Cada evento inclui os headers `X-Webhook-Event`
        e `X-Hub-Signature` (HMAC-SHA256 do corpo JSON).
      operationId: createWebhook
      parameters:
        - $ref: '#/components/parameters/CompanyCnpjDigits'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookCreateRequest'
      responses:
        '201':
          description: Webhook criado
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/WebhookCreateResponseData'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    delete:
      tags: [Webhooks]
      summary: Remover webhook
      operationId: deleteWebhook
      parameters:
        - $ref: '#/components/parameters/CompanyCnpjDigits'
        - name: id
          in: query
          required: true
          schema:
            type: integer
          description: Identificador do webhook retornado no cadastro
      responses:
        '200':
          description: Removido com sucesso
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Token obtido em `POST /api/auth`. Nas demais rotas, envie também o header `Company-Cnpj`
        com o CNPJ retornado em `data.companies[].document` (não use ID interno da empresa).

  parameters:
    CompanyCnpj:
      name: Company-Cnpj
      in: header
      required: true
      schema:
        type: string
        example: "12345678000199"
      description: CNPJ da empresa (com ou sem máscara)
    CompanyCnpjDigits:
      name: Company-Cnpj
      in: header
      required: true
      schema:
        type: string
        pattern: '^\d{11,14}$'
        example: "12345678000199"
      description: CNPJ da empresa somente com dígitos (11 a 14 caracteres)
    TransporterCnpj:
      name: Transporter-Cnpj
      in: header
      required: false
      schema:
        type: string
        example: "98765432000111"
      description: CNPJ da transportadora vinculada à empresa do contexto
    TransporterCnpjRequired:
      name: Transporter-Cnpj
      in: header
      required: true
      schema:
        type: string
        example: "98765432000111"
      description: |
        CNPJ da transportadora vinculada à empresa informada em `Company-Cnpj`.
        Obrigatório em integrações servidor a servidor; opcional para contas de transportadora (CNPJ resolvido pelo token).
    TransporterCnpjDigits:
      name: Transporter-Cnpj
      in: header
      required: false
      schema:
        type: string
        pattern: '^\d{14}$'
        example: "98765432000111"
      description: CNPJ da transportadora somente com 14 dígitos
    OperationId:
      name: Operation-Id
      in: header
      required: false
      schema:
        type: integer
        example: 3
      description: Identificador da operação logística configurada na empresa (`Company-Cnpj`)
    Direction:
      name: Direction
      in: header
      required: false
      schema:
        $ref: '#/components/schemas/DeliveryDirection'
      description: Fluxo da entrega (padrão forward)

  responses:
    BadRequest:
      description: Dados inválidos
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
          example:
            status: 400
            message: Dados incompletos.
    Unauthorized:
      description: Token ausente, inválido ou expirado
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
          example:
            status: 401
            message: Token expirado. Faça login novamente em POST /api/auth.
    Forbidden:
      description: Sem permissão para o recurso
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
          example:
            status: 403
            message: Acesso negado. Sem permissão para criar entregas.
    NotFound:
      description: Recurso não encontrado
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
    TooManyRequests:
      description: Limite de tentativas excedido (login)
      headers:
        Retry-After:
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'

  schemas:
    ApiResponse:
      type: object
      required: [status, message]
      properties:
        status:
          type: integer
          description: Código HTTP da resposta (repetido no corpo JSON)
          example: 200
        message:
          type: string
          example: Operação realizada com sucesso.
        data:
          description: Payload específico do endpoint (quando houver)

    DeliveryDirection:
      type: string
      enum: [forward, reverse]
      default: forward
      description: forward = entrega | reverse = devolução

    UserType:
      type: string
      enum: [internal, client, transporter]
      description: |
        Perfil da conta: `internal` = usuário da empresa embarcadora,
        `client` = portal do cliente, `transporter` = transportadora.

    PermissionSlug:
      type: string
      description: Identificador da permissão do usuário na empresa
      enum:
        - delivery_create
        - delivery_import_xml
        - occurrence_insert
        - audit_upload_xml
        - freight_quote_view
        - insert_location
        - webhook_view
        - webhook_create
        - "*"

    AuthRequest:
      type: object
      required: [email, password]
      properties:
        email:
          type: string
          format: email
        password:
          type: string
          format: password

    AuthUser:
      type: object
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string
          format: email
        type:
          $ref: '#/components/schemas/UserType'
        transporter_id:
          type: integer
          nullable: true
          description: Preenchido quando o usuário pertence a uma transportadora
        customer_id:
          type: integer
          nullable: true
          description: Preenchido quando o usuário pertence a um cliente

    CompanyAccess:
      type: object
      required: [name, document, is_default, role, permissions]
      description: Empresa vinculada ao usuário. Identifique o tenant pelo CNPJ (`document`), não por ID numérico.
      properties:
        name:
          type: string
          example: EMPRESA EXEMPLO LTDA
        document:
          type: string
          description: CNPJ da empresa — valor a enviar no header `Company-Cnpj` nas demais requisições
          example: "12345678000199"
        logo:
          type: string
          format: uri
          nullable: true
        is_default:
          type: boolean
        role:
          type: string
          description: Código do perfil de acesso na empresa
          example: company_admin
        role_name:
          type: string
          description: "Nome legível do perfil (ex.: Administrador)"
        permissions:
          type: array
          items:
            $ref: '#/components/schemas/PermissionSlug'

    AuthResponseData:
      type: object
      description: |
        Payload do login. Use `companies[].document` como contexto de empresa (`Company-Cnpj`);
        o identificador numérico interno da empresa não é retornado nesta API.
      properties:
        token:
          type: string
          description: Token Bearer (JWT) para as demais requisições
        expires_in:
          type: integer
          description: Segundos até expiração
          example: 300
        expires_at:
          type: string
          format: date-time
        user:
          $ref: '#/components/schemas/AuthUser'
        companies:
          type: array
          items:
            $ref: '#/components/schemas/CompanyAccess'

    CustomerInput:
      type: object
      required: [name, document]
      properties:
        name:
          type: string
          example: CLIENTE EXEMPLO LTDA
        document:
          type: string
          description: CPF ou CNPJ (somente números, sem pontuação)
          example: "12345678000199"
        email:
          type: string
          format: email
          nullable: true
        phone:
          type: string
          nullable: true

    LocationInput:
      type: object
      required: [zip_code]
      properties:
        name:
          type: string
          example: ENDEREÇO PRINCIPAL
        zip_code:
          type: string
          example: "01310100"
        address:
          type: string
        number:
          type: string
        complement:
          type: string
        neighborhood:
          type: string
        city:
          type: string
        state:
          type: string
          maxLength: 2
          example: SP
        ibge_code:
          type: string
          description: Código IBGE do município
        latitude:
          type: number
          format: double
        longitude:
          type: number
          format: double

    InvoiceInput:
      type: object
      properties:
        key:
          type: string
          description: Chave NF-e (44 dígitos)
          pattern: '^\d{44}$'
        number:
          type: string
        series:
          type: string
        value:
          type: number
          format: double
          description: Valor da NF
        weight:
          type: number
          format: double
          description: Peso em kg
        volumes:
          type: integer
          minimum: 1
          default: 1

    CreateDeliveryRequest:
      type: object
      required: [customer, location]
      properties:
        customer:
          $ref: '#/components/schemas/CustomerInput'
        location:
          $ref: '#/components/schemas/LocationInput'
        invoices:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceInput'
        description:
          type: string
        notes:
          type: string
        tracking_code:
          type: string
          description: Código customizado; gerado automaticamente se omitido
          example: "#TRK-A1B2-C3D4"

    CreateDeliveryResponseData:
      type: object
      properties:
        delivery_id:
          type: integer
        tracking_code:
          type: string
        transporter_document:
          type: string
          nullable: true
        direction:
          $ref: '#/components/schemas/DeliveryDirection'
        operation_id:
          type: integer
          nullable: true

    CreateDeliveryXmlRequest:
      type: object
      required: [xml]
      properties:
        xml:
          type: string
          format: binary
          description: Arquivo XML da NF-e (máx. 10 MB)

    CreateDeliveryXmlResponseData:
      allOf:
        - $ref: '#/components/schemas/CreateDeliveryResponseData'
        - type: object
          properties:
            invoice_key:
              type: string
            customer:
              type: string
              description: Nome do destinatário extraído do XML

    CreateOccurrenceRequest:
      type: object
      required: [occurrence_type_id]
      properties:
        delivery_id:
          type: integer
          description: Identificador numérico da entrega no Traceable
        tracking_code:
          type: string
        invoice_key:
          type: string
          description: Chave NF-e (44 dígitos)
        occurrence_type_id:
          type: string
          description: |
            Código de integração do tipo de ocorrência (campo "Código integração" no cadastro da empresa).
            Ex.: `ENTREGUE`, `3`. Não envie o ID numérico interno do painel web.
          example: ENTREGUE
        notes:
          type: string
        latitude:
          type: string
          description: |
            Latitude WGS84 (opcional). Decimal com ponto; intervalo -90 a 90.
            Omita ou deixe vazio se não houver GPS; se informada, deve ser válida (par com longitude).
          example: "-23.550520"
        longitude:
          type: string
          description: |
            Longitude WGS84 (opcional). Decimal com ponto; intervalo -180 a 180.
            Omita ou deixe vazio se não houver GPS; se informada, deve ser válida (par com latitude).
          example: "-46.633308"
        plate:
          type: string
          description: Atualiza veículo na entrega se cadastrado na frota
        receiver_name:
          type: string
          description: Obrigatório para tipos finais (POD)
        receiver_document:
          type: string
          description: Obrigatório para tipos finais (POD)
        proof_image:
          type: string
          format: binary
          description: JPG ou PNG, máx. 5 MB — obrigatório para status final
        signature_image:
          type: string
          format: binary
          description: Assinatura JPG ou PNG opcional

    CreateOccurrenceResponseData:
      type: object
      properties:
        occurrence_id:
          type: integer
        delivery_id:
          type: integer

    ImportCteRequest:
      type: object
      required: [xml_file]
      properties:
        xml_file:
          type: string
          format: binary
          description: XML do CT-e (máx. 10 MB)

    ImportCteResponseData:
      type: object
      properties:
        id:
          type: integer
        cte_number:
          type: string
        final_status:
          type: string
        transporter_document:
          type: string

    FreightQuoteSearchType:
      type: string
      enum: [cep, city]
      default: cep

    FreightQuoteRequest:
      type: object
      required: [operation_id, weight, invoice_value]
      properties:
        operation_id:
          type: integer
        weight:
          type: string
          description: Peso em kg (aceita formato BR ou US)
          example: "12,5"
        invoice_value:
          type: string
          description: Valor da nota
          example: "1500.50"
        search_type:
          $ref: '#/components/schemas/FreightQuoteSearchType'
        zip_code:
          type: string
          description: Obrigatório se search_type = cep
        ibge_code:
          type: string
          description: Obrigatório se search_type = city
        city_name:
          type: string
        direction:
          $ref: '#/components/schemas/DeliveryDirection'
        customer_cnpj:
          type: string
          description: CNPJ do cliente para aplicar regras de frete negociadas (opcional)

    TransporterSummary:
      type: object
      properties:
        name:
          type: string
        document:
          type: string

    CostBreakdown:
      type: object
      properties:
        tariff:
          type: number
          format: double
        weight_calc:
          type: number
          format: double
        ad_valorem:
          type: number
          format: double
        gris:
          type: number
          format: double
        dispatch:
          type: number
          format: double
        toll:
          type: number
          format: double

    QuoteItem:
      type: object
      properties:
        transporter:
          $ref: '#/components/schemas/TransporterSummary'
        table_name:
          type: string
        region_name:
          type: string
        total_cost:
          type: number
          format: double
        sla_hours:
          type: integer
        cost_breakdown:
          $ref: '#/components/schemas/CostBreakdown'

    QuoteHighlight:
      type: object
      properties:
        transporter_name:
          type: string
        transporter_document:
          type: string
        cost:
          type: number
          format: double
        sla_hours:
          type: integer

    FreightQuoteResponseData:
      type: object
      properties:
        request_info:
          type: object
          properties:
            direction:
              $ref: '#/components/schemas/DeliveryDirection'
        summary:
          type: object
          properties:
            cheapest:
              $ref: '#/components/schemas/QuoteHighlight'
            fastest:
              $ref: '#/components/schemas/QuoteHighlight'
        quotes:
          type: array
          items:
            $ref: '#/components/schemas/QuoteItem'

    FleetVehicleUpdate:
      type: object
      required: [lat, lng]
      properties:
        vehicle_id:
          type: integer
          description: Identificador do veículo cadastrado na frota Traceable
        id_integration:
          type: string
          description: Código do veículo no seu rastreador ou TMS (alternativa a `vehicle_id` e `plate`)
        plate:
          type: string
        lat:
          type: number
          format: double
        lng:
          type: number
          format: double
        speed:
          type: integer
          default: 0
        timestamp:
          type: string
          description: Data/hora da posição (YYYY-MM-DD HH:mm:ss)

    FleetGeolocationRequest:
      type: object
      required: [vehicles]
      properties:
        vehicles:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/FleetVehicleUpdate'

    FleetGeolocationError:
      type: object
      properties:
        index:
          type: integer
        identifier:
          type: string
        msg:
          type: string

    FleetGeolocationResponseData:
      type: object
      properties:
        total:
          type: integer
        success:
          type: integer
        failed:
          type: integer
        errors:
          type: array
          items:
            $ref: '#/components/schemas/FleetGeolocationError'

    WebhookEventType:
      type: string
      enum:
        - DeliveryCreated
        - OccurrenceCreated
        - AuditCreated
        - AuditScore

    WebhookCreateRequest:
      type: object
      required: [url, events]
      properties:
        url:
          type: string
          format: uri
        events:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/WebhookEventType'

    WebhookEndpoint:
      type: object
      properties:
        id:
          type: integer
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            $ref: '#/components/schemas/WebhookEventType'
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time

    WebhookCreateResponseData:
      type: object
      properties:
        id:
          type: integer
        secret:
          type: string
          description: Segredo para validar X-Hub-Signature (exibido apenas na criação)
        events:
          type: array
          items:
            $ref: '#/components/schemas/WebhookEventType'

security:
  - bearerAuth: []
