openapi: 3.1.0 info: title: API do Atende360 version: "1.0" summary: Contatos, campanhas, ligações, atendimentos digitais e pesquisas da sua conta. description: >- A API do Atende360 deixa o sistema do cliente (CRM, ERP, BI) ler e alterar dados da conta. Cada chave de API é criada no console, em Administração › Chaves de API, e só faz o que o administrador liberou. Respostas em JSON (UTF-8); datas e horas em ISO 8601, em UTC. contact: name: Atende360 url: https://atende360.ia.br/contato/ email: contato@atende360.ia.br servers: - url: https://api.atende360.ia.br security: - chaveDeAPI: [] tags: - name: Conta - name: Contatos - name: Campanhas - name: Ligações - name: Atendimentos digitais - name: Pesquisas paths: /v1/me: get: operationId: verChave tags: [Conta] summary: Ver a chave em uso description: >- Diz qual chave fez a chamada, de qual conta ela é e o que pode fazer. Use para testar a integração logo depois de criar a chave. x-permission: any x-request-example: path: /v1/me responses: "200": description: A chave é válida. content: application/json: example: key: id: 0b6c2f1e-5d1a-4c55-9a43-1f0f6b3d2a71 name: CRM Pipedrive prefix: a360_Pk2v expiresAt: null allowedIps: [] tenant: id: clinica-bem-viver name: Clínica Bem Viver permissions: contacts: write campaigns: write calls: none conversations: none surveys: none rateLimit: perMinute: 120 /v1/contacts: get: operationId: listarContatos tags: [Contatos] summary: Listar contatos description: >- Lista os contatos da conta, do mais recente para o mais antigo. A busca olha nome, telefone, documento e e-mail. x-permission: contacts:read parameters: - { name: q, in: query, schema: { type: string }, description: Busca por nome, telefone, documento ou e-mail. } - { name: tag, in: query, schema: { type: string }, description: Só contatos com esta etiqueta. } - { name: limit, in: query, schema: { type: integer, default: 50, maximum: 200 }, description: Quantos trazer. Padrão 50, máximo 200. } - { name: offset, in: query, schema: { type: integer, default: 0 }, description: Quantos pular, para a próxima página. } x-request-example: path: /v1/contacts query: { q: mariana, limit: 20 } responses: "200": description: Página de contatos, mesmo vazia. content: application/json: example: contacts: - id: c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10 name: Mariana Alves kind: person document: "12345678909" company: "" tags: [paciente, convenio] identities: - { kind: phone, value: "5511987654321" } - { kind: email, value: mariana@example.com } attendances30d: 3 lastAttendance: { channel: whatsapp, startedAt: "2026-10-27T18:31:00Z", protocol: "20261027000184", live: false } channels: [voice, whatsapp] revision: 4 createdAt: "2026-09-14T13:02:11Z" updatedAt: "2026-10-27T18:40:03Z" total: 1 post: operationId: criarContato tags: [Contatos] summary: Criar contato description: >- Cria o contato e devolve o registro completo. No console, o contato aparece criado por “API · nome da chave”. Se um telefone ou e-mail já tinha atendimentos sem contato, eles passam para o contato novo e linkedHistory diz quantos. x-permission: contacts:write requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ContatoEntrada" } x-request-example: path: /v1/contacts body: name: Mariana Alves document: "12345678909" tags: [paciente] identities: - { kind: phone, value: "+5511987654321" } - { kind: email, value: mariana@example.com } responses: "201": description: Criado. O cabeçalho ETag traz a revisão. content: application/json: example: contact: id: c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10 name: Mariana Alves kind: person document: "12345678909" company: "" tags: [paciente] identities: - { kind: phone, value: "5511987654321" } - { kind: email, value: mariana@example.com } attendances30d: 0 channels: [] revision: 1 createdAt: "2026-10-28T14:02:11Z" updatedAt: "2026-10-28T14:02:11Z" notes: "" createdByName: API · CRM Pipedrive attendances: [] linkedHistory: 0 "422": { $ref: "#/components/responses/Invalido" } /v1/contacts/{id}: get: operationId: verContato tags: [Contatos] summary: Ver um contato description: >- Traz o contato com observações e os últimos atendimentos. O cabeçalho ETag traz a revisão para usar no If-Match ao alterar. x-permission: contacts:read parameters: - { $ref: "#/components/parameters/Id" } x-request-example: path: /v1/contacts/c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10 responses: "200": description: Contato encontrado. content: application/json: example: id: c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10 name: Mariana Alves kind: person document: "12345678909" company: "" tags: [paciente, convenio] identities: - { kind: phone, value: "5511987654321" } attendances30d: 3 channels: [voice, whatsapp] revision: 4 createdAt: "2026-09-14T13:02:11Z" updatedAt: "2026-10-27T18:40:03Z" notes: Prefere contato à tarde. createdByName: API · CRM Pipedrive attendances: - { id: 5f1c2e9a-0b3d-4c7e-8a6f-2d9b1e0c3a74, protocol: "20261027000184", channel: whatsapp, direction: inbound, startedAt: "2026-10-27T18:31:00Z", live: false, identityKind: phone, identity: "5511987654321", handledBy: Paula Reis } "404": { $ref: "#/components/responses/NaoEncontrado" } put: operationId: atualizarContato tags: [Contatos] summary: Atualizar contato description: >- Substitui os dados do contato: mande o registro inteiro, não só o que mudou. A revisão lida vai no If-Match; se alguém alterou o contato antes, a resposta é 412. x-permission: contacts:write parameters: - { $ref: "#/components/parameters/Id" } - { $ref: "#/components/parameters/IfMatch" } requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ContatoEntrada" } x-request-example: path: /v1/contacts/c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10 ifMatch: "4" body: name: Mariana Alves Souza document: "12345678909" tags: [paciente, convenio] identities: - { kind: phone, value: "+5511987654321" } responses: "200": description: Atualizado; a revisão sobe. content: application/json: example: contact: { id: c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10, name: Mariana Alves Souza, revision: 5 } linkedHistory: 0 "412": { $ref: "#/components/responses/RevisaoMudou" } "428": { $ref: "#/components/responses/FaltaRevisao" } "422": { $ref: "#/components/responses/Invalido" } /v1/contacts/{id}/attendances: get: operationId: historicoDoContato tags: [Contatos] summary: Histórico do contato description: >- Ligações e conversas digitais do contato, da mais recente para a mais antiga, com o protocolo, quem atendeu e as notas de CSAT e NPS quando houver. x-permission: contacts:read parameters: - { $ref: "#/components/parameters/Id" } - { name: channel, in: query, schema: { type: string }, description: "Só um canal: voice, whatsapp, telegram, site ou email." } - { name: from, in: query, schema: { type: string, format: date-time }, description: "Início, em RFC 3339 (2026-10-01T00:00:00-03:00)." } - { name: to, in: query, schema: { type: string, format: date-time }, description: Fim, em RFC 3339. } x-request-example: path: /v1/contacts/c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10/attendances query: { channel: whatsapp } responses: "200": description: Histórico, mesmo vazio. content: application/json: example: attendances: - id: 5f1c2e9a-0b3d-4c7e-8a6f-2d9b1e0c3a74 protocol: "20261027000184" channel: whatsapp direction: inbound startedAt: "2026-10-27T18:31:00Z" endedAt: "2026-10-27T18:52:40Z" live: false identityKind: phone identity: "5511987654321" conversationId: a7c2e9f1-3b5d-4e8a-9c1f-6d2b0e4a8c35 channelName: WhatsApp da recepção messages: 14 handledBy: Paula Reis groupName: Recepção csat: 5 contact: { id: c8d1e0a4-2b7f-4e8e-9d1c-6a5b4f3e2d10, name: Mariana Alves, linkedBy: auto } "404": { $ref: "#/components/responses/NaoEncontrado" } /v1/campaigns: get: operationId: listarCampanhas tags: [Campanhas] summary: Listar campanhas description: >- As campanhas do discador com a situação e o andamento do mailing. status pode ser draft (rascunho), running, paused, stopped (encerrada por alguém) ou completed (o mailing acabou). x-permission: campaigns:read x-request-example: path: /v1/campaigns responses: "200": description: Lista, mesmo vazia. content: application/json: example: version: 1 items: - id: 7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47 name: Retorno de exames description: Pacientes com exame pronto destinationKind: group destinationName: Recepção status: running maxLines: 10 maxAttempts: 3 retryIntervalMinutes: 60 windowStartMinute: 540 windowEndMinute: 1080 weekdays: [1, 2, 3, 4, 5] timezone: America/Sao_Paulo mailing: { total: 1204, pending: 388, dialing: 6, done: 790, exhausted: 18, suppressed: 2, ready: 371, blocked: 0 } revision: 7 createdAt: "2026-10-20T12:00:00Z" updatedAt: "2026-10-28T13:10:00Z" /v1/campaigns/{id}: get: operationId: verCampanha tags: [Campanhas] summary: Ver uma campanha description: Configuração, situação e andamento de uma campanha. O cabeçalho ETag traz a revisão. x-permission: campaigns:read parameters: - { $ref: "#/components/parameters/Id" } x-request-example: path: /v1/campaigns/7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47 responses: "200": description: Campanha encontrada. content: application/json: example: id: 7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47 name: Retorno de exames status: running destinationKind: group maxLines: 10 mailing: { total: 1204, pending: 388, dialing: 6, done: 790, exhausted: 18, suppressed: 2, ready: 371, blocked: 0 } dialable: true revision: 7 "404": { $ref: "#/components/responses/NaoEncontrado" } /v1/campaigns/{id}/contacts: get: operationId: verMailing tags: [Campanhas] summary: Ver o mailing description: >- Contatos do mailing com a situação de cada um: pending (na fila), dialing (em ligação), done (concluído), exhausted (acabaram as tentativas) ou suppressed (retirado). x-permission: campaigns:read parameters: - { $ref: "#/components/parameters/Id" } - { name: status, in: query, schema: { type: string }, description: Só contatos nesta situação. } - { name: search, in: query, schema: { type: string }, description: Busca por nome, telefone ou código do cliente. } - { name: limit, in: query, schema: { type: integer, default: 50, maximum: 500 }, description: Padrão 50, máximo 500. } - { name: offset, in: query, schema: { type: integer, default: 0 }, description: Quantos pular. } x-request-example: path: /v1/campaigns/7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47/contacts query: { status: pending, limit: 100 } responses: "200": description: Página do mailing. content: application/json: example: items: - id: e41b6c9a-0d2f-4a8e-b7c3-5f1d9e2a6b80 phone: "5511987654321" name: Mariana Alves document: "" customerCode: PAC-1042 extra: { exame: Hemograma } priority: 0 status: pending attempts: 0 lastDisposition: "" nextAttemptAt: "2026-10-28T14:00:00Z" revision: 1 total: 388 post: operationId: incluirNoMailing tags: [Campanhas] summary: Incluir números no mailing description: >- Acrescenta contatos ao mailing da campanha. Números repetidos e números da blocklist não entram, e a resposta conta cada caso. Até 20.000 contatos por chamada; o que passar disso é ignorado e volta truncated true. x-permission: campaigns:write parameters: - { $ref: "#/components/parameters/Id" } requestBody: required: true content: application/json: schema: type: object required: [contacts] properties: contacts: type: array maxItems: 20000 description: Contatos a incluir. items: type: object required: [phone] properties: phone: { type: string, description: Telefone com DDD; aceita +55 na frente. } name: { type: string, description: Nome, mostrado ao atendente. } document: { type: string, description: CPF ou CNPJ. } customerCode: { type: string, description: Código do cliente no seu sistema. } extra: { type: object, additionalProperties: { type: string }, description: Campos livres, mostrados ao atendente na ligação. } priority: { type: integer, description: Maior liga antes. } x-request-example: path: /v1/campaigns/7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47/contacts body: contacts: - { phone: "+5511987654321", name: Mariana Alves, customerCode: PAC-1042, extra: { exame: Hemograma } } - { phone: "+5521998877665", name: João Pereira } responses: "200": description: Processado; veja os contadores. content: application/json: example: added: 2 duplicate: 0 rejected: 0 blocked: 0 reasons: [] mailing: { total: 1206, pending: 390, dialing: 6, done: 790, exhausted: 18, suppressed: 2, ready: 373, blocked: 0 } truncated: false "404": { $ref: "#/components/responses/NaoEncontrado" } "422": { $ref: "#/components/responses/Invalido" } /v1/campaigns/{id}/start: post: operationId: iniciarCampanha tags: [Campanhas] summary: Iniciar campanha description: >- Coloca a campanha para discar. Ela só liga dentro da janela de horário configurada. Mande a revisão da campanha no If-Match; a resposta traz a campanha com a revisão nova. x-permission: campaigns:write parameters: - { $ref: "#/components/parameters/Id" } - { $ref: "#/components/parameters/IfMatch" } x-request-example: method: POST path: /v1/campaigns/7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47/start ifMatch: "7" responses: "200": { $ref: "#/components/responses/CampanhaAtualizada" } "409": { $ref: "#/components/responses/Conflito" } "412": { $ref: "#/components/responses/RevisaoMudou" } /v1/campaigns/{id}/pause: post: operationId: pausarCampanha tags: [Campanhas] summary: Pausar campanha description: >- Para de discar sem encerrar: as ligações em curso terminam e a campanha volta a discar quando for iniciada de novo. Mande a revisão no If-Match. x-permission: campaigns:write parameters: - { $ref: "#/components/parameters/Id" } - { $ref: "#/components/parameters/IfMatch" } x-request-example: method: POST path: /v1/campaigns/7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47/pause ifMatch: "8" responses: "200": { $ref: "#/components/responses/CampanhaAtualizada" } "409": { $ref: "#/components/responses/Conflito" } "412": { $ref: "#/components/responses/RevisaoMudou" } /v1/campaigns/{id}/stop: post: operationId: encerrarCampanha tags: [Campanhas] summary: Encerrar campanha description: >- Encerra a campanha de vez: ela não volta a discar. Para continuar o mesmo mailing, crie outra campanha no console. Mande a revisão no If-Match. x-permission: campaigns:write parameters: - { $ref: "#/components/parameters/Id" } - { $ref: "#/components/parameters/IfMatch" } x-request-example: method: POST path: /v1/campaigns/7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47/stop ifMatch: "9" responses: "200": { $ref: "#/components/responses/CampanhaAtualizada" } "409": { $ref: "#/components/responses/Conflito" } "412": { $ref: "#/components/responses/RevisaoMudou" } /v1/conversations: get: operationId: listarLigacoes tags: [Ligações] summary: Listar ligações description: >- Ligações recebidas e feitas, inclusive as atendidas pela IA, da mais recente para a mais antiga. Para a próxima página, repita a chamada com before_started_at e before_id do último item; quando vier menos que o limit, acabou. x-permission: calls:read parameters: - { name: date_from, in: query, schema: { type: string, format: date }, description: "Primeiro dia, AAAA-MM-DD, no fuso de São Paulo. Vai junto com date_to." } - { name: date_to, in: query, schema: { type: string, format: date }, description: "Último dia, AAAA-MM-DD. Vai junto com date_from." } - { name: phone, in: query, schema: { type: string }, description: Número do cliente. } - { name: direction, in: query, schema: { type: string, enum: [inbound, outbound] }, description: inbound (recebida) ou outbound (feita). } - { name: campaign_id, in: query, schema: { type: string, format: uuid }, description: Só ligações desta campanha. } - { name: protocol, in: query, schema: { type: string }, description: Protocolo do atendimento. } - { name: limit, in: query, schema: { type: integer, default: 50, maximum: 100 }, description: Padrão 50, máximo 100. } - { name: before_started_at, in: query, schema: { type: string, format: date-time }, description: "Cursor: startedAt do último item, em RFC 3339." } - { name: before_id, in: query, schema: { type: string, format: uuid }, description: "Cursor: id do último item." } x-request-example: path: /v1/conversations query: { date_from: "2026-10-28", date_to: "2026-10-28", direction: inbound, limit: 50 } responses: "200": description: Página de ligações. content: application/json: example: version: 1 conversations: - id: 3f2a8c1d-6b4e-4a9f-8c2d-1e0b7a6f5d43 callId: 9a1c4e7f-2d3b-5c6a-8e9f-0b1a2c3d4e5f phone: "5511987654321" did: "551123910055" direction: inbound answered: true endReason: completed durationSeconds: 184 startedAt: "2026-10-28T13:58:02Z" lastMessageAt: "2026-10-28T14:01:06Z" messageCount: 12 preview: Queria remarcar meu exame de amanhã. hasRecording: true agentName: Recepção IA groupName: Recepção campaignId: "" protocol: "20261028000231" "400": { $ref: "#/components/responses/Requisicao" } /v1/conversations/{id}: get: operationId: verLigacao tags: [Ligações] summary: Ver uma ligação description: >- Detalhe da ligação com a transcrição: cada fala do cliente (user) e da IA (assistant), na ordem, e os eventos do fluxo (event), como transferência e encerramento. x-permission: calls:read parameters: - { $ref: "#/components/parameters/Id" } x-request-example: path: /v1/conversations/3f2a8c1d-6b4e-4a9f-8c2d-1e0b7a6f5d43 responses: "200": description: Ligação encontrada. content: application/json: example: id: 3f2a8c1d-6b4e-4a9f-8c2d-1e0b7a6f5d43 callId: 9a1c4e7f-2d3b-5c6a-8e9f-0b1a2c3d4e5f phone: "5511987654321" direction: inbound answered: true durationSeconds: 184 startedAt: "2026-10-28T13:58:02Z" hasRecording: true protocol: "20261028000231" messages: - { role: assistant, content: "Olá! Aqui é a recepção da Clínica Bem Viver. Como posso ajudar?", createdAt: "2026-10-28T13:58:04Z" } - { role: user, content: Queria remarcar meu exame de amanhã., createdAt: "2026-10-28T13:58:09Z" } "404": { $ref: "#/components/responses/NaoEncontrado" } /v1/conversations/{id}/recording-url: get: operationId: linkDaGravacao tags: [Ligações] summary: Link da gravação description: >- Gera um link para ouvir a gravação. O link vale 15 minutos: guarde o id da ligação, não o link, e peça outro quando precisar. x-permission: calls:read parameters: - { $ref: "#/components/parameters/Id" } x-request-example: path: /v1/conversations/3f2a8c1d-6b4e-4a9f-8c2d-1e0b7a6f5d43/recording-url responses: "200": description: Link pronto. content: application/json: example: url: "https://storage.example.com/gravacoes/9a1c4e7f.wav?X-Amz-Expires=900&X-Amz-Signature=3b1f…" "404": description: A ligação não existe ou não foi gravada. /v1/digital/conversations: get: operationId: listarAtendimentos tags: [Atendimentos digitais] summary: Listar atendimentos description: >- Conversas de WhatsApp, Telegram, chat do site e e-mail, da mais recente para a mais antiga. status é bot (com a IA ou o fluxo), queued (na fila), assigned (com um atendente) ou closed. x-permission: conversations:read parameters: - { name: status, in: query, schema: { type: string }, description: "Uma ou mais situações separadas por vírgula: bot, queued, assigned, closed." } - { name: channelId, in: query, schema: { type: string, format: uuid }, description: Só conversas deste canal. } - { name: search, in: query, schema: { type: string }, description: Busca por nome, número ou protocolo. } - { name: limit, in: query, schema: { type: integer }, description: Quantas trazer. } x-request-example: path: /v1/digital/conversations query: { status: "queued,assigned", limit: 50 } responses: "200": description: Lista, mesmo vazia. content: application/json: example: version: 1 items: - id: a7c2e9f1-3b5d-4e8a-9c1f-6d2b0e4a8c35 channelId: f6847618-2c1e-4b3a-9d5f-7e0a1c2b3d4e contactIdentity: "5511987654321" contactName: Mariana Alves status: assigned assigneeName: Paula Reis preview: Pode ser às 15h? unreadCount: 1 pendingReply: true windowOpen: true lastMessageAt: "2026-10-28T14:01:37Z" createdAt: "2026-10-28T13:40:12Z" protocol: "20261028000187" revision: 12 /v1/digital/conversations/{id}: get: operationId: verAtendimento tags: [Atendimentos digitais] summary: Ver um atendimento description: >- A conversa com as mensagens, da mais antiga para a mais nova. authorKind diz quem escreveu: contact (o cliente), user (um atendente), bot (a IA ou o fluxo) ou system. x-permission: conversations:read parameters: - { $ref: "#/components/parameters/Id" } - { name: limit, in: query, schema: { type: integer, default: 200, maximum: 500 }, description: Mensagens a trazer. Padrão 200, máximo 500. } x-request-example: path: /v1/digital/conversations/a7c2e9f1-3b5d-4e8a-9c1f-6d2b0e4a8c35 responses: "200": description: Conversa encontrada. content: application/json: example: conversation: { id: a7c2e9f1-3b5d-4e8a-9c1f-6d2b0e4a8c35, contactName: Mariana Alves, status: assigned, protocol: "20261028000187" } messages: - { id: 1d7e3c5a-9b2f-4e6a-8c1d-0f3b5a7c9e21, direction: inbound, authorKind: contact, body: "Oi, queria remarcar meu exame.", status: received, createdAt: "2026-10-28T13:40:12Z" } - { id: 6b8a0c2e-4d1f-4a3b-9e5c-7f2d4b6a8c03, direction: outbound, authorKind: user, authorName: Paula Reis, body: "Claro! Temos amanhã às 15h.", status: read, createdAt: "2026-10-28T13:41:03Z" } "404": { $ref: "#/components/responses/NaoEncontrado" } /v1/reports/csat/responses: get: operationId: respostasCSAT tags: [Pesquisas] summary: Respostas de CSAT description: >- Notas de 1 a 5 dadas ao fim dos atendimentos digitais, com comentário, canal e atendente. Sem from e to, traz os últimos 7 dias. x-permission: surveys:read parameters: - { name: from, in: query, schema: { type: string, format: date }, description: "Primeiro dia, AAAA-MM-DD (São Paulo)." } - { name: to, in: query, schema: { type: string, format: date }, description: Último dia, AAAA-MM-DD. } - { name: score, in: query, schema: { type: string }, description: "Uma nota (1 a 5) ou uma faixa: low (1–2), mid (3), high (4–5)." } - { name: comments, in: query, schema: { type: string, enum: ["1"] }, description: 1 para só respostas com comentário. } - { name: channel_id, in: query, schema: { type: string, format: uuid }, description: Só este canal. } - { name: limit, in: query, schema: { type: integer, default: 100, maximum: 1000 }, description: Padrão 100, máximo 1.000. } - { name: offset, in: query, schema: { type: integer, default: 0 }, description: Quantas pular. } x-request-example: path: /v1/reports/csat/responses query: { from: "2026-10-01", to: "2026-10-28", comments: "1" } responses: "200": description: Página de respostas. content: application/json: example: version: 1 items: - surveyId: 2c4e6a8b-0d1f-4a3c-9e5b-7d9f1b3d5f70 conversationId: a7c2e9f1-3b5d-4e8a-9c1f-6d2b0e4a8c35 closedAt: "2026-10-28T14:10:02Z" answeredAt: "2026-10-28T14:12:40Z" contactName: Mariana Alves contactIdentity: "5511987654321" channelName: WhatsApp da recepção channelKind: whatsapp attendantKind: user attendantName: Paula Reis groupName: Recepção status: answered score: 5 comment: Atendimento rápido! total: 1 limit: 100 offset: 0 "400": { $ref: "#/components/responses/Requisicao" } /v1/reports/nps/responses: get: operationId: respostasNPS tags: [Pesquisas] summary: Respostas de NPS description: >- Notas de 0 a 10 de recomendação. category já vem calculada: promoter (9 e 10), passive (7 e 8) ou detractor (0 a 6). Sem from e to, traz os últimos 7 dias. x-permission: surveys:read parameters: - { name: from, in: query, schema: { type: string, format: date }, description: "Primeiro dia, AAAA-MM-DD (São Paulo)." } - { name: to, in: query, schema: { type: string, format: date }, description: Último dia, AAAA-MM-DD. } - { name: category, in: query, schema: { type: string, enum: [promoter, passive, detractor] }, description: Só esta categoria. } - { name: unhandled, in: query, schema: { type: string, enum: ["1"] }, description: 1 para só detratores que ninguém tratou ainda. } - { name: comments, in: query, schema: { type: string, enum: ["1"] }, description: 1 para só respostas com comentário. } - { name: limit, in: query, schema: { type: integer, default: 100, maximum: 1000 }, description: Padrão 100, máximo 1.000. } - { name: offset, in: query, schema: { type: integer, default: 0 }, description: Quantas pular. } x-request-example: path: /v1/reports/nps/responses query: { from: "2026-10-01", category: detractor } responses: "200": description: Página de respostas. content: application/json: example: version: 1 items: - surveyId: 8e0a2c4e-6b1d-4f3a-9c5e-1b3d5f7a9c26 conversationId: b2d4f6a8-1c3e-4a5b-8d7f-9e0c2a4b6d81 closedAt: "2026-10-26T19:00:41Z" answeredAt: "2026-10-26T19:03:11Z" contactName: João Pereira contactIdentity: "5521998877665" channelName: WhatsApp da recepção channelKind: whatsapp attendantKind: user attendantName: Paula Reis groupName: Recepção status: answered score: 4 category: detractor comment: Demorou para responder. total: 1 limit: 100 offset: 0 "400": { $ref: "#/components/responses/Requisicao" } components: securitySchemes: chaveDeAPI: type: http scheme: bearer description: >- A chave de API criada no console (Administração › Chaves de API), no cabeçalho Authorization: Bearer a360_… parameters: Id: name: id in: path required: true schema: { type: string, format: uuid } description: Identificador do registro. IfMatch: name: If-Match in: header required: true schema: { type: string } description: Revisão atual entre aspas, como "4". Vem no ETag e no campo revision. schemas: Problema: type: object description: Corpo de todo erro, em application/problem+json. properties: code: { type: string, description: Código estável para o seu sistema tratar. } message: { type: string, description: Mensagem para gente ler. } fields: { type: object, additionalProperties: { type: string }, description: Motivo de cada campo inválido. } ContatoEntrada: type: object required: [name] properties: name: { type: string, description: Nome do contato. } kind: { type: string, enum: [person, company], default: person, description: Pessoa ou empresa. } document: { type: string, description: CPF ou CNPJ. } company: { type: string, description: Empresa do contato. } tags: { type: array, items: { type: string }, description: Etiquetas. } notes: { type: string, description: Observações internas. } identities: type: array description: Formas de contato. O telefone vai no formato internacional, como +5511987654321. items: type: object required: [kind, value] properties: kind: { type: string, enum: [phone, email, telegram, site, instagram, facebook] } value: { type: string } label: { type: string, description: Rótulo opcional, como “trabalho”. } responses: NaoEncontrado: description: O registro não existe nesta conta. content: application/problem+json: example: { code: resource_not_found, message: resource was not found } Invalido: description: Algum campo veio errado; fields diz qual e por quê. content: application/problem+json: example: { code: validation_failed, message: revise the highlighted fields, fields: { name: Informe o nome. } } RevisaoMudou: description: Alguém alterou o registro antes. Leia de novo e repita. content: application/problem+json: example: { code: revision_mismatch, message: resource changed; reload before saving } FaltaRevisao: description: Faltou o cabeçalho If-Match. content: application/problem+json: example: { code: revision_required, message: If-Match with the current revision is required } Conflito: description: A mudança não vale no estado atual, como iniciar uma campanha encerrada. content: application/problem+json: example: { code: resource_conflict, message: an equivalent resource already exists } Requisicao: description: Um parâmetro veio em formato inválido. content: application/problem+json: example: { code: invalid_request, message: date_from and date_to must use YYYY-MM-DD } CampanhaAtualizada: description: A campanha com a situação e a revisão novas. content: application/json: example: { id: 7d3e9b20-4c1a-4f6e-9b8d-2a5c0e1f3b47, name: Retorno de exames, status: running, revision: 8 }