{
  "openapi": "3.1.0",
  "info": {
    "title": "INMETRO Vehicle Data Agent API",
    "version": "1.1.0",
    "description": "API controlada para deduplica\u00E7\u00E3o, cat\u00E1logo limpo, normaliza\u00E7\u00E3o e enriquecimento t\u00E9cnico da base PBEV."
  },
  "servers": [
    {
      "url": "https://data-enrichment-agent.goldicard.net.br"
    }
  ],
  "security": [
    {
      "AgentApiKey": []
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "Health",
        "summary": "Verifica API e banco.",
        "tags": [
          "System"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        }
      }
    },
    "/api/pbev/dedupe/preview": {
      "post": {
        "operationId": "PreviewDuplicates",
        "summary": "Lista grupos de duplicidade sem alterar dados.",
        "tags": [
          "PBEV"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DedupePreviewRequest"
              }
            }
          }
        }
      }
    },
    "/api/pbev/catalog/preview": {
      "post": {
        "operationId": "PreviewCleanVehicleCatalog",
        "summary": "Pr\u00E9-visualiza normaliza\u00E7\u00E3o e split sem gravar.",
        "tags": [
          "Catalog"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogPreviewRequest"
              }
            }
          }
        }
      }
    },
    "/api/pbev/catalog/rebuild": {
      "post": {
        "operationId": "RebuildCleanVehicleCatalog",
        "summary": "Recria o cat\u00E1logo limpo a partir da lista suja.",
        "tags": [
          "Catalog"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogRebuildRequest"
              }
            }
          }
        }
      }
    },
    "/api/pbev/catalog/pending-review": {
      "post": {
        "operationId": "GetCleanCatalogPendingReview",
        "summary": "Lista itens do cat\u00E1logo que exigem revis\u00E3o.",
        "tags": [
          "Catalog"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogPendingReviewRequest"
              }
            }
          }
        }
      }
    },
    "/api/pbev/catalog/apply-normalization-batch": {
      "post": {
        "operationId": "ApplyCleanCatalogNormalizationBatch",
        "summary": "Aplica corre\u00E7\u00F5es de normaliza\u00E7\u00E3o revisadas.",
        "tags": [
          "Catalog"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogApplyNormalizationBatchRequest"
              }
            }
          }
        }
      }
    },
    "/api/pbev/pipeline/rebuild-clean-catalog": {
      "post": {
        "operationId": "RebuildCleanCatalogPipeline",
        "summary": "Executa dedupe mark-only opcional e recria cat\u00E1logo limpo.",
        "tags": [
          "Catalog"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CleanCatalogPipelineRequest"
              }
            }
          }
        }
      }
    },
    "/api/pbev/enrichment/missing": {
      "post": {
        "operationId": "GetMissingEnrichmentCandidates",
        "summary": "Lista candidatos a enriquecimento t\u00E9cnico.",
        "tags": [
          "Enrichment"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MissingEnrichmentQuery"
              }
            }
          }
        }
      }
    },
    "/api/pbev/enrichment/discover-urls": {
      "post": {
        "operationId": "DiscoverTechnicalSpecUrls",
        "summary": "Descobre URLs de ficha t\u00E9cnica validadas.",
        "tags": [
          "Enrichment"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DiscoverTechnicalSpecUrlsRequest"
              }
            }
          }
        }
      }
    },
    "/api/pbev/enrichment/scrape-url": {
      "post": {
        "operationId": "ScrapeFichaTecnicaUrl",
        "summary": "Extrai dados candidatos de uma URL p\u00FAblica.",
        "tags": [
          "Enrichment"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScrapeUrlRequest"
              }
            }
          }
        }
      }
    },
    "/api/agent/autonomous/runs/{runId}": {
      "get": {
        "operationId": "GetAutonomousAgentRun",
        "summary": "Consulta uma execu\u00E7\u00E3o aut\u00F4noma.",
        "tags": [
          "Autonomous Agent"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "parameters": [
          {
            "name": "runId",
            "in": "path",
            "required": true,
            "description": "RunId da execu\u00E7\u00E3o.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/agent/autonomous/dedupe/mark-only": {
      "post": {
        "operationId": "AutonomousDedupeMarkOnly",
        "summary": "Marca duplicados sem excluir linhas.",
        "tags": [
          "Autonomous Agent"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutonomousDedupeRequest"
              }
            }
          }
        }
      }
    },
    "/api/agent/autonomous/enrichment/apply-batch": {
      "post": {
        "operationId": "AutonomousApplyEnrichmentBatch",
        "summary": "Aplica enriquecimentos com evid\u00EAncia.",
        "tags": [
          "Autonomous Agent"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutonomousEnrichmentBatchRequest"
              }
            }
          }
        }
      }
    },
    "/api/agent/autonomous/rollback": {
      "post": {
        "operationId": "RollbackAutonomousRun",
        "summary": "Executa rollback de uma execu\u00E7\u00E3o.",
        "tags": [
          "Autonomous Agent"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing API key"
          },
          "403": {
            "description": "Invalid API key"
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutonomousRollbackRequest"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "AgentApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Agent-Key"
      }
    },
    "schemas": {
      "DedupePreviewRequest": {
        "type": "object",
        "properties": {
          "keyColumns": {
            "type": "array",
            "description": "Colunas da chave de duplicidade.",
            "items": {
              "type": "string"
            }
          },
          "take": {
            "type": "integer",
            "format": "int32",
            "description": "Quantidade m\u00E1xima retornada.",
            "default": 100
          }
        },
        "additionalProperties": false
      },
      "MissingEnrichmentQuery": {
        "type": "object",
        "properties": {
          "take": {
            "type": "integer",
            "format": "int32",
            "description": "Quantidade m\u00E1xima retornada.",
            "default": 100
          },
          "skip": {
            "type": "integer",
            "format": "int32",
            "description": "Offset de pagina\u00E7\u00E3o.",
            "default": 0
          },
          "onlyRowsWithoutTankCapacity": {
            "type": "boolean",
            "description": "Apenas sem tanque.",
            "default": true
          },
          "onlyRowsWithMissingConsumption": {
            "type": "boolean",
            "description": "Apenas com consumo ausente.",
            "default": false
          },
          "vehicleEnergyGroup": {
            "type": "string",
            "description": "Grupo energ\u00E9tico.",
            "enum": [
              "combustion",
              "electric",
              "hybrid",
              "special",
              "all"
            ],
            "default": "combustion"
          }
        },
        "additionalProperties": false
      },
      "DiscoverTechnicalSpecUrlsRequest": {
        "type": "object",
        "properties": {
          "pbevId": {
            "type": "integer",
            "format": "int32",
            "description": "ID em PBEV_CONCILIADO."
          },
          "take": {
            "type": "integer",
            "format": "int32",
            "description": "M\u00E1ximo de URLs aceitas.",
            "default": 5
          },
          "source": {
            "type": "string",
            "description": "Fonte controlada.",
            "enum": [
              "all",
              "carrosnaweb",
              "shopcar",
              "olhonocarro"
            ],
            "default": "all"
          },
          "validatePageContent": {
            "type": "boolean",
            "description": "Validar conte\u00FAdo da p\u00E1gina.",
            "default": true
          },
          "saveScrapeCandidates": {
            "type": "boolean",
            "description": "Salvar candidatos sem aplicar.",
            "default": false
          },
          "seedUrls": {
            "type": "array",
            "description": "URLs diretas opcionais para validar.",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false,
        "required": [
          "pbevId"
        ]
      },
      "ScrapeUrlRequest": {
        "type": "object",
        "properties": {
          "pbevId": {
            "type": "integer",
            "format": "int32",
            "description": "ID em PBEV_CONCILIADO."
          },
          "url": {
            "type": "string",
            "description": "URL p\u00FAblica da ficha t\u00E9cnica."
          },
          "sourceName": {
            "type": "string",
            "description": "Nome da fonte."
          },
          "saveCandidate": {
            "type": "boolean",
            "description": "Salvar candidato extra\u00EDdo.",
            "default": true
          }
        },
        "additionalProperties": false,
        "required": [
          "pbevId",
          "url"
        ]
      },
      "CatalogPreviewRequest": {
        "type": "object",
        "properties": {
          "take": {
            "type": "integer",
            "format": "int32",
            "description": "Quantidade m\u00E1xima retornada.",
            "default": 50
          },
          "skip": {
            "type": "integer",
            "format": "int32",
            "description": "Offset de pagina\u00E7\u00E3o.",
            "default": 0
          },
          "includeMarkedDuplicates": {
            "type": "boolean",
            "description": "Inclui linhas j\u00E1 marcadas duplicadas.",
            "default": false
          },
          "fromPbevId": {
            "type": "integer",
            "format": "int32",
            "description": "ID inicial opcional."
          },
          "toPbevId": {
            "type": "integer",
            "format": "int32",
            "description": "ID final opcional."
          }
        },
        "additionalProperties": false
      },
      "CatalogRebuildRequest": {
        "type": "object",
        "properties": {
          "includeMarkedDuplicates": {
            "type": "boolean",
            "description": "Inclui duplicados marcados.",
            "default": false
          },
          "fromPbevId": {
            "type": "integer",
            "format": "int32",
            "description": "ID inicial opcional."
          },
          "toPbevId": {
            "type": "integer",
            "format": "int32",
            "description": "ID final opcional."
          },
          "resetCatalog": {
            "type": "boolean",
            "description": "Limpa cat\u00E1logo antes de recriar.",
            "default": true
          },
          "minAutoConfidence": {
            "type": "number",
            "format": "double",
            "description": "Confian\u00E7a m\u00EDnima autom\u00E1tica.",
            "default": 0.9
          }
        },
        "additionalProperties": false
      },
      "CleanCatalogPipelineRequest": {
        "type": "object",
        "properties": {
          "runDedupeFirst": {
            "type": "boolean",
            "description": "Executa dedupe mark-only antes.",
            "default": true
          },
          "maxDedupeRows": {
            "type": "integer",
            "format": "int32",
            "description": "M\u00E1ximo de duplicados marcados.",
            "default": 10000
          },
          "includeMarkedDuplicates": {
            "type": "boolean",
            "description": "Inclui duplicados no cat\u00E1logo.",
            "default": false
          },
          "resetCatalog": {
            "type": "boolean",
            "description": "Limpa cat\u00E1logo antes de recriar.",
            "default": true
          },
          "minAutoConfidence": {
            "type": "number",
            "format": "double",
            "description": "Confian\u00E7a m\u00EDnima autom\u00E1tica.",
            "default": 0.9
          }
        },
        "additionalProperties": false
      },
      "CatalogPendingReviewRequest": {
        "type": "object",
        "properties": {
          "take": {
            "type": "integer",
            "format": "int32",
            "description": "Quantidade m\u00E1xima retornada.",
            "default": 100
          },
          "skip": {
            "type": "integer",
            "format": "int32",
            "description": "Offset de pagina\u00E7\u00E3o.",
            "default": 0
          },
          "status": {
            "type": "string",
            "description": "Status buscado.",
            "enum": [
              "NeedsReview",
              "AutoNormalized",
              "ApprovedByAgent",
              "all"
            ],
            "default": "NeedsReview"
          },
          "maxConfidence": {
            "type": "number",
            "format": "double",
            "description": "Confian\u00E7a m\u00E1xima opcional."
          }
        },
        "additionalProperties": false
      },
      "CatalogApplyNormalizationBatchRequest": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "description": "Corre\u00E7\u00F5es revisadas.",
            "items": {
              "$ref": "#/components/schemas/CatalogApplyNormalizationItem"
            }
          },
          "appliedBy": {
            "type": "string",
            "description": "Identifica\u00E7\u00E3o do aplicador.",
            "default": "gpt-actions"
          },
          "markAsApproved": {
            "type": "boolean",
            "description": "Marca como aprovado.",
            "default": true
          }
        },
        "additionalProperties": false,
        "required": [
          "items"
        ]
      },
      "CatalogApplyNormalizationItem": {
        "type": "object",
        "properties": {
          "catalogId": {
            "type": "integer",
            "format": "int32",
            "description": "ID do cat\u00E1logo limpo."
          },
          "marcaNorm": {
            "type": "string",
            "description": "Marca normalizada."
          },
          "modeloNorm": {
            "type": "string",
            "description": "Modelo normalizado."
          },
          "versaoNorm": {
            "type": "string",
            "description": "Vers\u00E3o normalizada."
          },
          "carroceriaNorm": {
            "type": "string",
            "description": "Carroceria normalizada."
          },
          "motorNorm": {
            "type": "string",
            "description": "Motor normalizado."
          },
          "cilindrada": {
            "type": "number",
            "format": "double",
            "description": "Cilindrada."
          },
          "valvulas": {
            "type": "integer",
            "format": "int32",
            "description": "N\u00FAmero de v\u00E1lvulas."
          },
          "combustivelNorm": {
            "type": "string",
            "description": "Combust\u00EDvel normalizado."
          },
          "transmissaoNorm": {
            "type": "string",
            "description": "Transmiss\u00E3o normalizada."
          },
          "confidence": {
            "type": "number",
            "format": "double",
            "description": "Confian\u00E7a entre 0 e 1.",
            "default": 0.95
          },
          "reason": {
            "type": "string",
            "description": "Justificativa da corre\u00E7\u00E3o."
          }
        },
        "additionalProperties": false,
        "required": [
          "catalogId",
          "confidence"
        ]
      },
      "AutonomousDedupeRequest": {
        "type": "object",
        "properties": {
          "keyColumns": {
            "type": "array",
            "description": "Colunas da chave de duplicidade.",
            "items": {
              "type": "string"
            }
          },
          "maxRows": {
            "type": "integer",
            "format": "int32",
            "description": "M\u00E1ximo de registros afetados.",
            "default": 100
          },
          "confidence": {
            "type": "number",
            "format": "double",
            "description": "Confian\u00E7a da decis\u00E3o.",
            "default": 1
          },
          "snapshot": {
            "type": "boolean",
            "description": "Criar snapshot antes.",
            "default": true
          }
        },
        "additionalProperties": false
      },
      "AutonomousEnrichmentBatchRequest": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "description": "Itens de enriquecimento.",
            "items": {
              "$ref": "#/components/schemas/AutonomousEnrichmentItem"
            }
          },
          "snapshot": {
            "type": "boolean",
            "description": "Criar snapshot antes.",
            "default": true
          },
          "appliedBy": {
            "type": "string",
            "description": "Identifica\u00E7\u00E3o do aplicador.",
            "default": "autonomous-agent"
          }
        },
        "additionalProperties": false,
        "required": [
          "items"
        ]
      },
      "AutonomousEnrichmentItem": {
        "type": "object",
        "properties": {
          "pbevId": {
            "type": "integer",
            "format": "int32",
            "description": "ID em PBEV_CONCILIADO."
          },
          "capacidadeTanqueLitros": {
            "type": "number",
            "format": "double",
            "description": "Tanque em litros."
          },
          "etanolCidadeKmL": {
            "type": "number",
            "format": "double",
            "description": "Etanol urbano km/l."
          },
          "etanolEstradaKmL": {
            "type": "number",
            "format": "double",
            "description": "Etanol rodovi\u00E1rio km/l."
          },
          "gasolinaDieselCidadeKmL": {
            "type": "number",
            "format": "double",
            "description": "Gasolina/diesel urbano km/l."
          },
          "gasolinaDieselEstradaKmL": {
            "type": "number",
            "format": "double",
            "description": "Gasolina/diesel rodovi\u00E1rio km/l."
          },
          "confidence": {
            "type": "number",
            "format": "double",
            "description": "Confian\u00E7a entre 0 e 1."
          },
          "sourceUrl": {
            "type": "string",
            "description": "URL da evid\u00EAncia."
          },
          "sourceName": {
            "type": "string",
            "description": "Nome da fonte."
          },
          "evidenceText": {
            "type": "string",
            "description": "Trecho de evid\u00EAncia."
          }
        },
        "additionalProperties": false,
        "required": [
          "pbevId",
          "confidence",
          "sourceUrl"
        ]
      },
      "AutonomousRollbackRequest": {
        "type": "object",
        "properties": {
          "runId": {
            "type": "string",
            "format": "uuid",
            "description": "RunId a desfazer."
          },
          "rollbackState": {
            "type": "boolean",
            "description": "Desfaz estado do agente.",
            "default": true
          },
          "rollbackEnrichment": {
            "type": "boolean",
            "description": "Desfaz enriquecimentos.",
            "default": true
          }
        },
        "additionalProperties": false,
        "required": [
          "runId"
        ]
      }
    }
  },
  "tags": [
    {
      "name": "System"
    },
    {
      "name": "PBEV"
    },
    {
      "name": "Catalog"
    },
    {
      "name": "Enrichment"
    },
    {
      "name": "Autonomous Agent"
    }
  ]
}