{
  "openapi": "3.1.0",
  "info": {
    "title": "IAReview Public API",
    "version": "1.1.1",
    "summary": "Partner REST API for feedbacks, tratativas (tickets), compilations, webhooks and CS metrics",
    "description": "API pública para integração B2B com a plataforma IAReview (NPS/CSAT e close-the-loop).\n\n## Autenticação\n1. Obtenha o UUID da conta (`X-Customer-Id`) e o `secretKey` no painel (**Configurações → Organização e API**).\n2. `POST /v1/signin-with-credentials` com headers `X-Customer-Id` e `secretKey`.\n3. Use `Authorization: Bearer <access_token>` e o **mesmo** `X-Customer-Id` nas demais rotas.\n4. O header `apiKey` ainda é aceito no login como sinônimo de `X-Customer-Id`. `secretKey` **não** vai no `Authorization`.\n\n## Feedbacks\n- `POST /v1/feedbacks` — cria avaliação **pendente** e devolve o link único. Não grava nota.\n- `POST /v1/feedbacks/invites` — o mesmo fluxo, com disparo de e-mail/WhatsApp quando o canal pede.\n- `GET /v1/feedbacks/{id}/{customerId}/form` — payload público da tela de resposta.\n- `PUT /v1/feedbacks/{id}/{customerId}/response` — o respondente envia a nota (público). Sucesso **201**.\n\n## Métricas\n`GET /v1/metrics/scores` e `GET /v1/metrics/cs` usam só `from` e `to` (UTC).\nSem esses params: últimos 30 dias. `productId` **não** é query — o breakdown por produto vem em `byProduct`.\n\n## Tickets\nTickets mapeiam a tratativa (recovery) de uma avaliação. O `{id}` é o `evaluationId`.\n`GET /v1/tickets/{id}` devolve a thread (mensagens, status, responsável, CSAT da tratativa).\n\n## Compilações\nInsights em lote gerados pelo cron (`default_analysis` / `monthly_analysis`).\n`compilation.ready` avisa quando o JSON completo já está em `GET /v1/compilations/{id}`.\n\n## Webhooks outbound\nEventos: `feedback.detractor_created`, `feedback.promoter_created`, `feedback.passive_created`,\n`ticket.replied_by_customer`, `ticket.status_changed`, `ticket.resolved`,\n`detractor.insight.ready`, `compilation.ready`. Formatos: `json`, `discord`, `slack`.\n",
    "contact": {
      "name": "IAReview",
      "url": "https://iareview.ai"
    },
    "license": {
      "name": "Proprietary"
    },
    "x-logo": {
      "url": "/static/landingPage.svg",
      "altText": "IAReview",
      "href": "https://iareview.ai",
      "backgroundColor": "transparent"
    }
  },
  "servers": [
    {
      "url": "https://api.iareview.ai",
      "description": "Production"
    },
    {
      "url": "https://api.iareview.online",
      "description": "Staging / alternate"
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "X-Customer-Id + secretKey → JWT; apiKey ainda aceito no login"
    },
    {
      "name": "Feedbacks",
      "description": "Listagem, ingestão, convite (link único) e resposta do cliente"
    },
    {
      "name": "Tickets",
      "description": "Tratativa (close-the-loop) via API"
    },
    {
      "name": "Compilations",
      "description": "Insights em lote (cron). GET lista/detalhe; webhook `compilation.ready` quando grava."
    },
    {
      "name": "Webhooks",
      "description": "Outbound POST. O campo `format` define o **corpo**, não o destino.\nURL de Discord/Slack com `format=json` recebe `{type,timestamp,data}`, não embed/Block Kit.\n\n- `json`: envelope + `X-IAReview-Signature` opcional (n8n, Zapier, API).\n- `discord`: Incoming Webhook (`username` + `embeds`).\n- `slack`: Incoming Webhook (`text` + Block Kit).\n\nTeste dispara cada evento assinado no formato salvo.\n"
    },
    {
      "name": "Metrics",
      "description": "KPIs de Customer Success e índices NPS/CSAT/CES já calculados"
    }
  ],
  "paths": {
    "/v1/signin-with-credentials": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Obter JWT com X-Customer-Id + secretKey",
        "description": "`X-Customer-Id` é o UUID do tenant (o mesmo das demais rotas).\n`secretKey` é a senha do client — **só** neste endpoint.\nO header `apiKey` ainda é aceito como sinônimo de `X-Customer-Id`.\n",
        "operationId": "signInWithCredentials",
        "security": [],
        "parameters": [
          {
            "name": "X-Customer-Id",
            "in": "header",
            "required": true,
            "description": "UUID do tenant (Keycloak client_id). Mesmo valor das demais rotas.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "11111111-1111-1111-1111-111111111111"
          },
          {
            "name": "secretKey",
            "in": "header",
            "required": true,
            "description": "Senha do client. Não usar no Authorization das outras rotas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "apiKey",
            "in": "header",
            "required": false,
            "description": "Aceito como sinônimo de X-Customer-Id (integrações antigas).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Token de acesso",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignInResponse"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas"
          }
        }
      }
    },
    "/v1/feedbacks": {
      "get": {
        "tags": [
          "Feedbacks"
        ],
        "summary": "Listar feedbacks (paginado / filtrável)",
        "description": "Paginação por `limit` + `offset` (não usa `page`).\nDatas: `createdDateStart`/`createdDateEnd` (criação do convite) e\n`respondedDateStart`/`respondedDateEnd` (quando o cliente respondeu).\n",
        "operationId": "listFeedbacks",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Itens por página. Default 15.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 15
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Itens a pular. Default 0.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "order",
            "in": "query",
            "description": "1 categoria A–Z, 2 categoria Z–A, 3 criação asc, 4 criação desc (default),\n5 resposta asc, 6 resposta desc.\n",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "4",
                "5",
                "6"
              ],
              "default": "4"
            }
          },
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Categoria do produto",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "product",
            "in": "query",
            "description": "Nome do produto (não é o UUID)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "evaluationType",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "NPS",
                "CSAT",
                "BOTH",
                "CES"
              ]
            }
          },
          {
            "name": "createdDateStart",
            "in": "query",
            "description": "YYYY-MM-DD ou RFC3339",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdDateEnd",
            "in": "query",
            "description": "YYYY-MM-DD ou RFC3339",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "respondedDateStart",
            "in": "query",
            "description": "YYYY-MM-DD ou RFC3339",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "respondedDateEnd",
            "in": "query",
            "description": "YYYY-MM-DD ou RFC3339",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moderationStatus",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "REJECTED",
                "APPROVED",
                "FLAGGED_AUTO"
              ]
            }
          },
          {
            "name": "npsClassification",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "PROMOTER",
                "NEUTRAL",
                "DETRACTOR"
              ]
            }
          },
          {
            "name": "csatClassification",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "SATISFIED",
                "NEUTRAL",
                "DISSATISFIED"
              ]
            }
          },
          {
            "name": "recoveryStatus",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "in_progress",
                "waiting_customer",
                "waiting_cs",
                "closed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lista paginada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackList"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Feedbacks"
        ],
        "summary": "Criar avaliação pendente (link único)",
        "description": "Mesmo handler de `POST /v1/evaluation`: cria avaliação **pendente** e devolve\n`link` + `id`. Não persiste NPS/CSAT/CES — a nota entra em\n`PUT /v1/feedbacks/{id}/{customerId}/response`.\n\nCanal default `api`. Para disparar e-mail/WhatsApp use `POST /v1/feedbacks/invites`.\n",
        "operationId": "createFeedback",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFeedbackRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Avaliação pendente criada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackCreated"
                }
              }
            }
          }
        }
      }
    },
    "/v1/feedbacks/{id}": {
      "get": {
        "tags": [
          "Feedbacks"
        ],
        "summary": "Obter feedback por ID",
        "description": "Inclui `recoveryStatus`, sentimento da moderação (`feelingScore`, `labelFeeling`)\ne o micro-insight persistido (`microInsight`) quando o detrator já teve insight gerado.\n",
        "operationId": "getFeedback",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          }
        ],
        "responses": {
          "200": {
            "description": "Detalhe do feedback",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feedback"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado"
          }
        }
      }
    },
    "/v1/feedbacks/invites": {
      "post": {
        "tags": [
          "Feedbacks"
        ],
        "summary": "Criar convite / link único",
        "description": "Cria avaliação pendente, devolve o link público e dispara e-mail/WhatsApp\nquando `channel` for `Email` ou `WhatsApp` e houver destinatário.\n",
        "operationId": "createFeedbackInvite",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFeedbackInviteRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Convite criado (inclui `link`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackCreated"
                }
              }
            }
          }
        }
      }
    },
    "/v1/feedbacks/{id}/{customerId}/form": {
      "get": {
        "tags": [
          "Feedbacks"
        ],
        "summary": "Payload público da tela de resposta",
        "description": "Sem JWT. Usado pela página `/review/{id}/{customerId}`.",
        "operationId": "getFeedbackForm",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          },
          {
            "$ref": "#/components/parameters/CustomerIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Dados para renderizar o formulário",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackForm"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado"
          }
        }
      }
    },
    "/v1/feedbacks/{id}/{customerId}/response": {
      "put": {
        "tags": [
          "Feedbacks"
        ],
        "summary": "Enviar resposta do cliente",
        "description": "Público (sem JWT). O respondente submete NPS/CSAT/CES no link único.",
        "operationId": "submitFeedbackResponse",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          },
          {
            "$ref": "#/components/parameters/CustomerIdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitFeedbackResponseRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Resposta gravada (texto `\"Resposta de avaliação enviada com sucesso!\"`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string",
                  "example": "Resposta de avaliação enviada com sucesso!"
                }
              }
            }
          },
          "400": {
            "description": "Já respondido ou payload inválido"
          }
        }
      }
    },
    "/v1/tickets/{id}": {
      "get": {
        "tags": [
          "Tickets"
        ],
        "summary": "Obter thread da tratativa",
        "description": "O `{id}` é o `evaluationId`. Devolve conversa, mensagens, status, responsável\ne CSAT da tratativa. Sem dump de e-mail no CSV — o objeto completo está aqui.\n",
        "operationId": "getTicket",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          }
        ],
        "responses": {
          "200": {
            "description": "Thread da tratativa. Sem conversa ainda, `messages` vem `[]` e `status` é o da avaliação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketThread"
                }
              }
            }
          },
          "404": {
            "description": "Feedback não encontrado"
          }
        }
      }
    },
    "/v1/tickets/{id}/reply": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Enviar e-mail de tratativa",
        "operationId": "replyTicket",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketReplyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "E-mail enfileirado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "conversationId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "messageId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "recoveryStatus": {
                      "type": "string"
                    },
                    "correlationToken": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/tickets/{id}/status": {
      "patch": {
        "tags": [
          "Tickets"
        ],
        "summary": "Atualizar status da tratativa",
        "description": "`RESOLVED` ou `CLOSED` → encerra (close).\n`IN_PROGRESS` ou `OPEN` → reabre.\n",
        "operationId": "patchTicketStatus",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketStatusRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status atualizado. `csatUrl` só existe se o close interno gerar token (o alias público não lê `sendCsat`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "recoveryStatus": {
                      "type": "string"
                    },
                    "csatSent": {
                      "type": "boolean"
                    },
                    "csatUrl": {
                      "type": "string"
                    },
                    "closedBy": {
                      "type": "string"
                    },
                    "reopenedBy": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/tickets/{id}/assign": {
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Atribuir tratativa a um atendente",
        "operationId": "assignTicket",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketAssignRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atribuído",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "assignedToEmail": {
                      "type": "string"
                    },
                    "assignedToUserId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/compilations": {
      "get": {
        "tags": [
          "Compilations"
        ],
        "summary": "Listar compilações de insights",
        "description": "Paginação `limit` + `offset`. Datas deste endpoint são `dateStart`/`dateEnd`\n(não `from`/`to`). Sucesso responde **201** (status do handler interno).\n",
        "operationId": "listCompilations",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 15
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "analysisType",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "default_analysis",
                "monthly_analysis"
              ]
            }
          },
          {
            "name": "dateStart",
            "in": "query",
            "description": "Início (YYYY-MM-DD ou RFC3339). Default 12 meses atrás.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateEnd",
            "in": "query",
            "description": "Fim (YYYY-MM-DD ou RFC3339). Default agora.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Lista paginada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompilationList"
                }
              }
            }
          }
        }
      }
    },
    "/v1/compilations/{id}": {
      "get": {
        "tags": [
          "Compilations"
        ],
        "summary": "Obter compilação por ID",
        "description": "Sucesso responde **201** (status do handler interno).",
        "operationId": "getCompilation",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          }
        ],
        "responses": {
          "201": {
            "description": "Compilação completa",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Compilation"
                }
              }
            }
          },
          "400": {
            "description": "ID inválido"
          }
        }
      }
    },
    "/v1/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Listar webhooks outbound",
        "operationId": "listWebhooks",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Lista",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Webhook"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Criar webhook outbound",
        "operationId": "createWebhook",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}": {
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Remover webhook",
        "operationId": "deleteWebhook",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ResourceId"
          }
        ],
        "responses": {
          "200": {
            "description": "Removido",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "deleted"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/metrics/scores": {
      "get": {
        "tags": [
          "Metrics"
        ],
        "summary": "NPS, CSAT e CES do período",
        "description": "Índices já calculados (mesma conta do painel V2). Só avaliações `APPROVED`.\nO recorte temporal usa `created_at`.\n\nA resposta traz o **geral da conta** em `nps` / `csat` / `ces` e, no mesmo\nobjeto, `byProduct`: um item por produto (`productId` + `productName` + as\nmesmas métricas). Não existe query de produto — o breakdown vem sempre.\n\nSem `from`/`to`: últimos 30 dias até agora (UTC).\n",
        "operationId": "getScoreMetrics",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DateFrom"
          },
          {
            "$ref": "#/components/parameters/DateTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Índices do período",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScoreMetrics"
                },
                "example": {
                  "from": "2026-09-01T00:00:00Z",
                  "to": "2026-10-01T00:00:00Z",
                  "nps": {
                    "score": 40,
                    "promoters": 7,
                    "neutrals": 1,
                    "detractors": 2,
                    "total": 10,
                    "byProduct": [
                      {
                        "productId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
                        "productName": "Loja A",
                        "score": 50,
                        "promoters": 3,
                        "neutrals": 0,
                        "detractors": 1,
                        "total": 4
                      }
                    ]
                  },
                  "csat": {
                    "score": 4.2,
                    "satisfied": 12,
                    "neutrals": 3,
                    "dissatisfied": 2,
                    "total": 17,
                    "byProduct": []
                  },
                  "ces": {
                    "score": 5.8,
                    "lowEffort": 8,
                    "neutrals": 2,
                    "highEffort": 1,
                    "total": 11,
                    "byProduct": []
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/metrics/cs": {
      "get": {
        "tags": [
          "Metrics"
        ],
        "summary": "Métricas de CS (FRT, MTTR, Churn Saved, CSAT tratativa)",
        "description": "Sem `from`/`to`: últimos 30 dias até agora (UTC).\n",
        "operationId": "getCSMetrics",
        "security": [
          {
            "BearerAuth": [],
            "CustomerIdHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DateFrom"
          },
          {
            "$ref": "#/components/parameters/DateTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Agregados do período",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CSMetrics"
                },
                "example": {
                  "from": "2026-09-01T00:00:00Z",
                  "to": "2026-10-01T00:00:00Z",
                  "avgFrtSeconds": 3600,
                  "avgMttrSeconds": 86400,
                  "closedCount": 10,
                  "resolutionConfirmedCount": 7,
                  "churnSavedRate": 0.7,
                  "avgTratativaCsat": 4.2,
                  "conversationCount": 12,
                  "byAttendant": [
                    {
                      "attendantEmail": "cs@acme.com",
                      "assignedCount": 8,
                      "closedCount": 6,
                      "avgFrtSeconds": 1800,
                      "avgMttrSeconds": 72000
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Access token (`access_token`) retornado por `/v1/signin-with-credentials`. Não é o secretKey.",
        "x-scalar-secret-token": "YOUR_ACCESS_TOKEN"
      },
      "CustomerIdHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Customer-Id",
        "description": "UUID do tenant (o mesmo usado no login). Não é o secretKey.",
        "x-scalar-secret-token": "YOUR_CUSTOMER_ID"
      }
    },
    "parameters": {
      "ResourceId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "UUID do recurso (`evaluationId` em tickets/feedbacks; ID da compilação em compilations).",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "CustomerIdPath": {
        "name": "customerId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "DateFrom": {
        "name": "from",
        "in": "query",
        "required": false,
        "description": "Início do período em UTC. `YYYY-MM-DD` ou RFC3339 (`2026-09-01T00:00:00Z`).\nOmitido: 30 dias atrás.\n",
        "schema": {
          "type": "string",
          "example": "2026-09-01"
        }
      },
      "DateTo": {
        "name": "to",
        "in": "query",
        "required": false,
        "description": "Fim do período em UTC. `YYYY-MM-DD` inclui o dia inteiro (vira meia-noite do dia seguinte).\nRFC3339 usa o instante informado. Omitido: agora.\n",
        "schema": {
          "type": "string",
          "example": "2026-10-01"
        }
      }
    },
    "schemas": {
      "SignInResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "expires_in": {
            "type": "integer"
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          }
        },
        "additionalProperties": true
      },
      "FeedbackList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Feedback"
            }
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "Feedback": {
        "type": "object",
        "description": "Avaliação com sentimento da moderação e micro-insight persistido.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "productId": {
            "type": "string",
            "format": "uuid"
          },
          "productName": {
            "type": "string"
          },
          "categoryProduct": {
            "type": "string"
          },
          "evaluationType": {
            "type": "string",
            "enum": [
              "NPS",
              "CSAT",
              "BOTH",
              "CES"
            ]
          },
          "npsScore": {
            "type": "number"
          },
          "evaluationNote": {
            "type": "number",
            "description": "Nota CSAT 1–5"
          },
          "cesScore": {
            "type": "number",
            "description": "Nota CES 1–7"
          },
          "npsClassification": {
            "type": "string",
            "enum": [
              "PROMOTER",
              "NEUTRAL",
              "DETRACTOR"
            ]
          },
          "csatClassification": {
            "type": "string",
            "enum": [
              "SATISFIED",
              "NEUTRAL",
              "DISSATISFIED"
            ]
          },
          "cesClassification": {
            "type": "string",
            "enum": [
              "LOW_EFFORT",
              "NEUTRAL",
              "HIGH_EFFORT"
            ]
          },
          "textAvaluation": {
            "type": "string"
          },
          "channelEvaluationSended": {
            "type": "string"
          },
          "customerId": {
            "type": "string",
            "format": "uuid"
          },
          "responderName": {
            "type": "string"
          },
          "responderEmail": {
            "type": "string"
          },
          "responderPhoneNumber": {
            "type": "string"
          },
          "dateTimeAvaluation": {
            "type": "string",
            "format": "date-time",
            "description": "Quando o cliente respondeu"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "recoveryStatus": {
            "type": "string",
            "enum": [
              "none",
              "in_progress",
              "waiting_customer",
              "waiting_cs",
              "closed"
            ]
          },
          "moderationStatus": {
            "type": "string"
          },
          "feelingScore": {
            "type": "string",
            "description": "Sentimento da resposta (pipeline de moderação)."
          },
          "labelFeeling": {
            "type": "string"
          },
          "microInsight": {
            "$ref": "#/components/schemas/MicroInsight"
          },
          "evaluationUrl": {
            "type": "string",
            "format": "uri"
          }
        },
        "additionalProperties": true
      },
      "MicroInsight": {
        "type": "object",
        "description": "Insight pontual do detrator (não inclui sentimento; esse vem de feelingScore).",
        "properties": {
          "version": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "ready",
              "failed"
            ]
          },
          "summary": {
            "type": "string"
          },
          "why": {
            "type": "string"
          },
          "causes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "suggestedAction": {
            "type": "string"
          },
          "confidence": {
            "type": "number"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TicketThread": {
        "type": "object",
        "properties": {
          "conversationId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string"
          },
          "primaryChannel": {
            "type": "string"
          },
          "messageCount": {
            "type": "integer"
          },
          "whatsappEligible": {
            "type": "boolean"
          },
          "canSendEmail": {
            "type": "boolean"
          },
          "assignedToEmail": {
            "type": "string"
          },
          "closedBy": {
            "type": "string"
          },
          "reopenedBy": {
            "type": "string"
          },
          "firstResponseAt": {
            "type": "string",
            "format": "date-time"
          },
          "resolvedAt": {
            "type": "string",
            "format": "date-time"
          },
          "resolutionConfirmed": {
            "type": "boolean"
          },
          "tratativaCsatScore": {
            "type": "integer"
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TicketMessage"
            }
          }
        }
      },
      "TicketMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "channel": {
            "type": "string"
          },
          "direction": {
            "type": "string"
          },
          "bodyText": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "sentByUserId": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Compilation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "customerId": {
            "type": "string",
            "format": "uuid"
          },
          "batchAnalysisType": {
            "type": "string",
            "enum": [
              "default_analysis",
              "monthly_analysis"
            ]
          },
          "dateTimeBatch": {
            "type": "string",
            "format": "date-time"
          },
          "totalReviews": {
            "type": "integer"
          },
          "positiveReviews": {
            "type": "integer"
          },
          "negativeReviews": {
            "type": "integer"
          },
          "neutralReviews": {
            "type": "integer"
          },
          "averageFeelingScore": {
            "type": "number"
          },
          "generalSentiment": {
            "type": "string"
          },
          "sentimentalTrends": {
            "type": "string"
          },
          "businessInsights": {
            "type": "string"
          },
          "businessTrends": {
            "type": "string"
          },
          "improvementSuggestions": {
            "type": "string"
          },
          "commonPositiveAspects": {
            "type": "string"
          },
          "commonNegativeAspects": {
            "type": "string"
          },
          "commonRelevantKeywords": {
            "type": "string"
          },
          "commonIdentifiedTopics": {
            "type": "string"
          },
          "analysisComments": {
            "type": "string"
          },
          "monthlyComparisonSummary": {
            "type": "string"
          },
          "trendAnalysisSummary": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "CompilationList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Compilation"
            }
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "CreateFeedbackRequest": {
        "type": "object",
        "required": [
          "productId",
          "productName",
          "categoryProduct",
          "evaluationType"
        ],
        "properties": {
          "productId": {
            "type": "string",
            "format": "uuid"
          },
          "productName": {
            "type": "string"
          },
          "categoryProduct": {
            "type": "string"
          },
          "evaluationType": {
            "type": "string",
            "enum": [
              "NPS",
              "CSAT",
              "BOTH",
              "CES"
            ]
          },
          "responderName": {
            "type": "string"
          },
          "responderEmail": {
            "type": "string",
            "format": "email"
          },
          "responderPhoneNumber": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "description": "Default `api`. Não dispara e-mail/WhatsApp.",
            "default": "api",
            "example": "api"
          }
        }
      },
      "FeedbackCreated": {
        "type": "object",
        "properties": {
          "link": {
            "type": "string",
            "format": "uri"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "evaluationType": {
            "type": "string"
          },
          "channelAvaluationSended": {
            "type": "string"
          },
          "productId": {
            "type": "string",
            "format": "uuid"
          },
          "productName": {
            "type": "string"
          },
          "customerId": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "categoryProduct": {
            "type": "string"
          }
        }
      },
      "FeedbackForm": {
        "type": "object",
        "properties": {
          "productDescription": {
            "type": "string"
          },
          "productName": {
            "type": "string"
          },
          "productImageUrl": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "customerLogoUrl": {
            "type": "string"
          },
          "feedbackConfig": {
            "type": "object"
          },
          "evaluation": {
            "type": "object",
            "description": "Avaliação pendente (campos internos do formulário público)"
          }
        }
      },
      "CreateFeedbackInviteRequest": {
        "type": "object",
        "required": [
          "productId",
          "productName",
          "categoryProduct",
          "evaluationType",
          "channel"
        ],
        "properties": {
          "productId": {
            "type": "string",
            "format": "uuid"
          },
          "productName": {
            "type": "string"
          },
          "categoryProduct": {
            "type": "string"
          },
          "evaluationType": {
            "type": "string",
            "enum": [
              "NPS",
              "CSAT",
              "BOTH",
              "CES"
            ]
          },
          "channel": {
            "type": "string",
            "description": "Preferido. `Email` ou `WhatsApp` dispara o envio. Outros valores só geram o link.",
            "example": "Email"
          },
          "channelEvaluationSended": {
            "type": "string",
            "description": "Aceito como sinônimo de `channel`"
          },
          "name": {
            "type": "string"
          },
          "responderName": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "responderEmail": {
            "type": "string",
            "format": "email"
          },
          "phoneNumber": {
            "type": "string",
            "example": "+5511999881234"
          },
          "responderPhoneNumber": {
            "type": "string"
          },
          "comments": {
            "type": "string"
          },
          "templateName": {
            "type": "string"
          }
        }
      },
      "SubmitFeedbackResponseRequest": {
        "type": "object",
        "properties": {
          "npsScore": {
            "type": "number",
            "minimum": 0,
            "maximum": 10
          },
          "evaluationNote": {
            "type": "number",
            "description": "CSAT 1–5",
            "minimum": 1,
            "maximum": 5
          },
          "cesScore": {
            "type": "number",
            "description": "CES 1–7",
            "minimum": 1,
            "maximum": 7
          },
          "textAvaluation": {
            "type": "string"
          },
          "responderName": {
            "type": "string"
          },
          "responderEmail": {
            "type": "string",
            "format": "email"
          },
          "languageAvaluation": {
            "type": "string"
          }
        }
      },
      "TicketReplyRequest": {
        "type": "object",
        "required": [
          "subject",
          "body"
        ],
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "email"
            ],
            "default": "email"
          }
        }
      },
      "TicketStatusRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "RESOLVED",
              "CLOSED",
              "IN_PROGRESS",
              "OPEN"
            ]
          }
        }
      },
      "TicketAssignRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "userId": {
            "type": "string"
          }
        }
      },
      "WebhookInput": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Deve ser HTTPS"
          },
          "format": {
            "type": "string",
            "enum": [
              "json",
              "discord",
              "slack"
            ],
            "default": "json",
            "description": "Corpo do POST. `json` sempre envia o envelope, mesmo se a URL for Discord/Slack.\n"
          },
          "authType": {
            "type": "string",
            "enum": [
              "none",
              "bearer",
              "basic",
              "header"
            ],
            "default": "none"
          },
          "authHeaderName": {
            "type": "string"
          },
          "authUsername": {
            "type": "string"
          },
          "authSecret": {
            "type": "string"
          },
          "signingSecret": {
            "type": "string",
            "description": "HMAC para format=json"
          },
          "events": {
            "type": "array",
            "description": "Vazio → default `detractor.insight.ready`.",
            "items": {
              "type": "string",
              "enum": [
                "feedback.detractor_created",
                "feedback.promoter_created",
                "feedback.passive_created",
                "ticket.replied_by_customer",
                "ticket.status_changed",
                "ticket.resolved",
                "detractor.insight.ready",
                "compilation.ready",
                "*"
              ]
            }
          },
          "enabled": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "Webhook": {
        "type": "object",
        "description": "Resposta sanitizada. Segredos nunca voltam; só `hasAuthSecret` / `hasSigningSecret`.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "customerId": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "format": {
            "type": "string",
            "enum": [
              "json",
              "discord",
              "slack"
            ]
          },
          "authType": {
            "type": "string"
          },
          "authHeaderName": {
            "type": "string"
          },
          "authUsername": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "enabled": {
            "type": "boolean"
          },
          "hasAuthSecret": {
            "type": "boolean"
          },
          "hasSigningSecret": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookDeliveryJson": {
        "type": "object",
        "required": [
          "type",
          "timestamp",
          "data"
        ],
        "description": "Corpo quando format=json (também se a URL for Discord/Slack).\n`compilation.ready` traz `compilationId`, `type`, `createdAt`, `totalReviews`,\n`generalSentiment` e `insightsUrl`; o JSON completo vem em GET `/v1/compilations/{id}`.\n",
        "properties": {
          "type": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object"
          }
        },
        "example": {
          "type": "feedback.promoter_created",
          "timestamp": "2026-10-20T16:00:00Z",
          "data": {
            "customerId": "11111111-1111-1111-1111-111111111111",
            "evaluationId": "22222222-2222-2222-2222-222222222222",
            "productName": "Atendimento",
            "evaluationType": "NPS",
            "npsScore": 10,
            "classification": "PROMOTER",
            "textPreview": "ótimo",
            "reviewUrl": "https://iareview.ai/app/reviews/item/22222222-2222-2222-2222-222222222222"
          }
        }
      },
      "WebhookDeliveryDiscord": {
        "type": "object",
        "description": "Corpo quando format=discord (Incoming Webhook).",
        "example": {
          "username": "IAReview",
          "embeds": [
            {
              "title": "Promotor",
              "description": "ótimo",
              "color": 1483361,
              "url": "https://iareview.ai/app/reviews/item/22222222-2222-2222-2222-222222222222"
            }
          ]
        }
      },
      "WebhookDeliverySlack": {
        "type": "object",
        "description": "Corpo quando format=slack (Incoming Webhook + Block Kit).",
        "example": {
          "text": "Promotor — ótimo",
          "blocks": [
            {
              "type": "header",
              "text": {
                "type": "plain_text",
                "text": "Promotor"
              }
            }
          ]
        }
      },
      "ScoreMetrics": {
        "type": "object",
        "required": [
          "from",
          "to",
          "nps",
          "csat",
          "ces"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "nps": {
            "$ref": "#/components/schemas/NpsMetric"
          },
          "csat": {
            "$ref": "#/components/schemas/CsatMetric"
          },
          "ces": {
            "$ref": "#/components/schemas/CesMetric"
          }
        }
      },
      "NpsMetric": {
        "type": "object",
        "properties": {
          "score": {
            "type": "number",
            "description": "(promotores% − detratores%), escala −100 a 100"
          },
          "promoters": {
            "type": "integer"
          },
          "neutrals": {
            "type": "integer"
          },
          "detractors": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "byProduct": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "productId": {
                  "type": "string",
                  "format": "uuid"
                },
                "productName": {
                  "type": "string"
                },
                "score": {
                  "type": "number"
                },
                "promoters": {
                  "type": "integer"
                },
                "neutrals": {
                  "type": "integer"
                },
                "detractors": {
                  "type": "integer"
                },
                "total": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "CsatMetric": {
        "type": "object",
        "properties": {
          "score": {
            "type": "number",
            "description": "Média 1–5"
          },
          "satisfied": {
            "type": "integer"
          },
          "neutrals": {
            "type": "integer"
          },
          "dissatisfied": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "byProduct": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "productId": {
                  "type": "string",
                  "format": "uuid"
                },
                "productName": {
                  "type": "string"
                },
                "score": {
                  "type": "number"
                },
                "satisfied": {
                  "type": "integer"
                },
                "neutrals": {
                  "type": "integer"
                },
                "dissatisfied": {
                  "type": "integer"
                },
                "total": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "CesMetric": {
        "type": "object",
        "properties": {
          "score": {
            "type": "number",
            "description": "Média CES 2.0 (1–7, maior = mais fácil)"
          },
          "lowEffort": {
            "type": "integer"
          },
          "neutrals": {
            "type": "integer"
          },
          "highEffort": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "byProduct": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "productId": {
                  "type": "string",
                  "format": "uuid"
                },
                "productName": {
                  "type": "string"
                },
                "score": {
                  "type": "number"
                },
                "lowEffort": {
                  "type": "integer"
                },
                "neutrals": {
                  "type": "integer"
                },
                "highEffort": {
                  "type": "integer"
                },
                "total": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "CSMetrics": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "avgFrtSeconds": {
            "type": "number"
          },
          "avgMttrSeconds": {
            "type": "number"
          },
          "closedCount": {
            "type": "integer"
          },
          "resolutionConfirmedCount": {
            "type": "integer"
          },
          "churnSavedRate": {
            "type": "number",
            "description": "resolutionConfirmedCount / closedCount"
          },
          "avgTratativaCsat": {
            "type": "number"
          },
          "conversationCount": {
            "type": "integer"
          },
          "byAttendant": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "attendantEmail": {
                  "type": "string"
                },
                "assignedCount": {
                  "type": "integer"
                },
                "closedCount": {
                  "type": "integer"
                },
                "avgFrtSeconds": {
                  "type": "number"
                },
                "avgMttrSeconds": {
                  "type": "number"
                }
              }
            }
          }
        }
      }
    }
  }
}
