Visão Geral

O endpoint /api/externalAPIs/public/tickets/getTickets permite buscar tickets usando um sistema de hierarquia de critérios inteligente, com priorização automática baseada nos parâmetros fornecidos.

O sistema usa uma lógica de prioridade hierárquica: ticketId (prioridade máxima) > leadId > conversationId (prioridade mínima).

Características Principais

  • Busca Hierárquica: Sistema de prioridade inteligente (ticketId > leadId > conversationId)
  • Dados Enriquecidos: Informações completas do ticket com entidades relacionadas
  • Filtros Avançados: Filtros por avatar, inclusão de eventos, fechados e deletados
  • Histórico de Eventos: Opção de incluir histórico completo de eventos
  • Performance Otimizada: Utiliza índices existentes do banco de dados

Casos de Uso

  • Recuperar ticket específico por ID
  • Obter todos os tickets de um lead/cliente
  • Obter todos os tickets de uma conversa
  • Filtrar tickets por avatar/agente específico
  • Construir dashboards e relatórios com dados completos

Endpoint

POST /api/externalAPIs/public/tickets/getTickets

Autenticação

  • Header: Authorization: Bearer <token>
  • Content-Type: application/json
  • Middleware: tolkyAuthMiddleware (resolve hostId automaticamente)

Parâmetros de Consulta

Identificadores (Prioridade Hierárquica)

ParâmetroTipoObrigatórioDescriçãoPrioridade
ticketIdstring (UUID)NãoID específico do ticket1 (Mais alta)
leadIdstring (UUID)NãoID do lead/cliente2
conversationIdstring (UUID)NãoID da conversa3 (Mais baixa)

Filtros Opcionais

ParâmetroTipoDescrição
avatarIdstring (UUID) | arrayFiltrar por avatar específico ou múltiplos avatares
includeEventsbooleanIncluir histórico de eventos (padrão: true)
includeClosedbooleanIncluir tickets fechados (padrão: true)
includeDeletedbooleanIncluir tickets deletados (padrão: false)

Regras de Negócio

  • Obrigatório: Estar autenticado (host filtrado pelo middleware)
  • Critério Mínimo: Pelo menos um entre ticketId, leadId ou conversationId
  • Prioridade: Se múltiplos identificadores forem fornecidos, o de maior prioridade prevalece
  • Host: hostId é resolvido automaticamente pelo middleware

Exemplos de Requisição

Buscar Ticket Específico

{
  "ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
  "includeEvents": true
}

Buscar por Lead

{
  "leadId": "5db2c5f7-16b7-40e5-9a0f-f7f0c69c3e77",
  "includeClosed": false,
  "includeEvents": true
}

Buscar por Conversa com Filtro de Avatar

{
  "conversationId": "0c8e3fa7-0601-4a75-9b9c-c1c919c50a8c",
  "avatarId": [
    "e0fe2a9f-7c1e-4c73-8c70-cb7b0f2e99e0",
    "a45b9ce4-9c57-4725-8a28-2252cd039699"
  ],
  "includeDeleted": false
}

Buscar Múltiplos Avatares

{
  "leadId": "5db2c5f7-16b7-40e5-9a0f-f7f0c69c3e77",
  "avatarId": "e0fe2a9f-7c1e-4c73-8c70-cb7b0f2e99e0",
  "includeEvents": true,
  "includeClosed": true
}

Resposta de Sucesso

{
  "code": 200,
  "success": true,
  "data": [
    {
      "id": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
      "protocol": "ABCD-1234",
      "subject": "Problema de conectividade",
      "description": "Usuário reporta dificuldades para acessar o sistema",
      "definitionOfDone": "Sistema funcionando normalmente",
      "status": {
        "name": "Em Progresso",
        "level": 2,
        "color": "#F6AD55",
        "isClosed": false
      },
      "createdAt": "2025-01-15T09:00:00.000Z",
      "updatedAt": "2025-01-15T10:30:00.000Z",
      "importance": 3,
      "importanceColor": "#F6AD55",
      "closed": false,
      "closedAt": null,
      "deleted": false,
      "hostId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "leadId": "5db2c5f7-16b7-40e5-9a0f-f7f0c69c3e77",
      "conversationId": "0c8e3fa7-0601-4a75-9b9c-c1c919c50a8c",
      "sessionId": "s1e2s3s4-i5o6-n789-0abc-def123456789",
      "avatarId": "e0fe2a9f-7c1e-4c73-8c70-cb7b0f2e99e0",
      "externalId": "EXT-12345",
      "movedByIa": false,
      "lastSeen": null,
      "lastSeenBy": null,
      "lastConversationUpdate": "2025-01-15T10:30:00.000Z",
      "assignedUser": {
        "id": "4a6b9f6e-0f2f-4e2b-9a77-98b0d64c4d11",
        "name": "João Silva"
      },
      "contact": {
        "name": "Maria Santos",
        "email": "maria@empresa.com",
        "phone": "55999998888"
      },
      "events": [
        {
          "id": "evt-789",
          "type": "status",
          "createdAt": "2025-01-15T09:00:00.000Z",
          "description": "Ticket criado automaticamente",
          "summary": "Status alterado para: Em Progresso",
          "pendingActions": null,
          "email": null,
          "wpp": null,
          "userId": "4a6b9f6e-0f2f-4e2b-9a77-98b0d64c4d11"
        },
        {
          "id": "evt-790",
          "type": "info",
          "createdAt": "2025-01-15T10:30:00.000Z",
          "description": "Ticket atribuído ao usuário João Silva",
          "summary": "Atribuição realizada",
          "pendingActions": null,
          "email": null,
          "wpp": null,
          "userId": "4a6b9f6e-0f2f-4e2b-9a77-98b0d64c4d11"
        }
      ],
      "ticketLevelId": "3fb2a9f0-5aa3-4f6d-8d37-c2a0b1d7b9a2"
    }
  ],
  "count": 1,
  "searchCriteria": {
    "ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
    "leadId": null,
    "conversationId": null,
    "hostId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "avatarId": null
  },
  "message": "Successfully retrieved 1 ticket(s)"
}

Estrutura dos Dados

Ticket Object

CampoTipoDescrição
idstring (UUID)ID único do ticket
protocolstringProtocolo/número do ticket
subjectstringAssunto do ticket
descriptionstringDescrição detalhada
definitionOfDonestringDefinição de pronto (DOD)
statusobjectStatus atual do ticket
status.namestringNome do status
status.levelnumberNível numérico do status
status.colorstringCor do status (hex)
status.isClosedbooleanSe o status indica fechamento
createdAtstringData de criação (ISO 8601)
updatedAtstringData da última atualização (ISO 8601)
importancenumberNível de importância (1-4)
importanceColorstringCor da importância (hex)
closedbooleanSe o ticket está fechado
closedAtstring | nullData de fechamento (ISO 8601)
deletedbooleanSe o ticket foi deletado
hostIdstring (UUID)ID do host
leadIdstring (UUID)ID do lead/cliente
conversationIdstring (UUID)ID da conversa
sessionIdstring (UUID)ID da sessão
avatarIdstring (UUID)ID do avatar responsável
externalIdstringID externo do ticket
movedByIabooleanSe foi movido por IA
lastSeenstring | nullÚltima visualização
lastSeenBystring | nullÚltimo usuário que visualizou
lastConversationUpdatestring | nullÚltima atualização da conversa
assignedUserobject | nullUsuário responsável
contactobjectDados do contato
eventsarrayHistórico de eventos
ticketLevelIdstring (UUID)ID do nível atual

AssignedUser Object

CampoTipoDescrição
idstring (UUID)ID do usuário
namestringNome do usuário

Contact Object

CampoTipoDescrição
namestringNome do contato
emailstringEmail do contato
phonestringTelefone do contato

Event Object

CampoTipoDescrição
idstring (UUID)ID único do evento
typestringTipo do evento (status, info, motivo)
createdAtstringData/hora do evento (ISO 8601)
descriptionstringDescrição do evento
summarystringResumo do evento
pendingActionsobject | nullAções pendentes
emailobject | nullDados de email
wppobject | nullDados de WhatsApp
userIdstring (UUID)ID do usuário responsável

Códigos de Erro

CódigoErroDescriçãoSolução
400MissingSearchParameterNenhum parâmetro de busca fornecidoFornecer pelo menos um identificador (ticketId, leadId ou conversationId)
403Invalid credentialsCredenciais inválidasVerificar token de autenticação
500GetTicketsErrorErro interno na buscaContatar suporte técnico

Exemplo com cURL

curl -X POST "$BASE_URL/api/externalAPIs/public/tickets/getTickets" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "leadId": "5db2c5f7-16b7-40e5-9a0f-f7f0c69c3e77",
    "includeEvents": true,
    "includeClosed": false
  }'

Exemplo de Integração Completa

class TicketRetriever {
  constructor(apiToken, baseUrl) {
    this.apiToken = apiToken;
    this.baseUrl = baseUrl;
  }

  async getTickets(params = {}) {
    try {
      const response = await fetch(`${this.baseUrl}/api/externalAPIs/public/tickets/getTickets`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.apiToken}`
        },
        body: JSON.stringify(params)
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(`Erro ${response.status}: ${error.message}`);
      }

      return await response.json();
    } catch (error) {
      console.error('Erro ao buscar tickets:', error);
      throw error;
    }
  }

  // Buscar ticket específico
  async getTicketById(ticketId, includeEvents = true) {
    return await this.getTickets({
      ticketId,
      includeEvents
    });
  }

  // Buscar tickets de um lead
  async getTicketsByLead(leadId, filters = {}) {
    return await this.getTickets({
      leadId,
      includeEvents: true,
      includeClosed: true,
      ...filters
    });
  }

  // Buscar tickets de uma conversa
  async getTicketsByConversation(conversationId, filters = {}) {
    return await this.getTickets({
      conversationId,
      includeEvents: true,
      includeClosed: true,
      ...filters
    });
  }

  // Buscar tickets por avatar
  async getTicketsByAvatar(avatarId, additionalFilters = {}) {
    return await this.getTickets({
      avatarId,
      includeEvents: true,
      includeClosed: true,
      ...additionalFilters
    });
  }

  // Buscar tickets abertos de um lead
  async getOpenTicketsByLead(leadId) {
    return await this.getTickets({
      leadId,
      includeEvents: true,
      includeClosed: false
    });
  }

  // Buscar tickets com eventos específicos
  async getTicketsWithEvents(criteria) {
    return await this.getTickets({
      ...criteria,
      includeEvents: true
    });
  }
}

// Uso da classe
const ticketRetriever = new TicketRetriever('seu_token_aqui', 'https://api.tolky.to');

// Exemplos de uso
async function examples() {
  try {
    // Buscar ticket específico
    const ticket = await ticketRetriever.getTicketById('b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a');
    console.log('Ticket encontrado:', ticket.data[0]);

    // Buscar tickets de um lead
    const leadTickets = await ticketRetriever.getTicketsByLead('5db2c5f7-16b7-40e5-9a0f-f7f0c69c3e77', {
      includeClosed: false
    });
    console.log(`Tickets abertos do lead: ${leadTickets.data.length}`);

    // Buscar tickets por avatar
    const avatarTickets = await ticketRetriever.getTicketsByAvatar('e0fe2a9f-7c1e-4c73-8c70-cb7b0f2e99e0');
    console.log(`Tickets do avatar: ${avatarTickets.data.length}`);

    // Buscar tickets de uma conversa específica
    const conversationTickets = await ticketRetriever.getTicketsByConversation('0c8e3fa7-0601-4a75-9b9c-c1c919c50a8c');
    console.log(`Tickets da conversa: ${conversationTickets.data.length}`);

    // Processar eventos dos tickets
    leadTickets.data.forEach(ticket => {
      if (ticket.events && ticket.events.length > 0) {
        console.log(`Ticket ${ticket.protocol} tem ${ticket.events.length} eventos`);
        ticket.events.forEach(event => {
          console.log(`- ${event.type}: ${event.description}`);
        });
      }
    });

  } catch (error) {
    console.error('Erro:', error.message);
  }
}

Sistema de Prioridade Hierárquica

O sistema implementa uma lógica de prioridade inteligente:

  1. ticketId (Prioridade 1): Busca direta por ID específico
  2. leadId (Prioridade 2): Busca todos os tickets de um lead
  3. conversationId (Prioridade 3): Busca todos os tickets de uma conversa

Importante: Forneça pelo menos um identificador (ticketId, leadId ou conversationId). Requisições sem identificadores resultarão em erro 400.

Dica: Use includeEvents=true para obter o histórico completo de eventos, útil para auditoria e acompanhamento detalhado.

Nota: O parâmetro includeDeleted=false por padrão exclui tickets deletados. Use includeDeleted=true apenas quando necessário para auditoria ou recuperação de dados.