Atualizar Ticket
Endpoint para atualizar campos de tickets e movê-los entre estágios do pipeline
Visão Geral
O endpoint /api/externalAPIs/public/tickets/updateTicket permite atualizar campos de tickets existentes e movê-los entre diferentes estágios do pipeline, com rastreamento automático de eventos de auditoria.
Este endpoint suporta duas operações: atualização de campos OU movimentação de estágio, ou ambas combinadas. A movimentação é executada após a atualização quando ambas são solicitadas.
Características Principais
- Operações Flexíveis: Atualização de campos, movimentação de estágio, ou ambas
- Campos Completos: Todos os campos do ticket podem ser atualizados
- Movimentação Inteligente: Move tickets entre estágios com rastreamento de motivos
- Eventos Automáticos: Cria automaticamente eventos de auditoria para todas as mudanças
- Integração HubSpot: Sincroniza estágios quando habilitado
Casos de Uso
- Atualizar informações do ticket durante o progresso do workflow
- Mover tickets entre estágios do pipeline
- Atribuir tickets a usuários específicos
- Fechar/abrir tickets com documentação adequada
- Operações automatizadas com workflows
Endpoint
POST /api/externalAPIs/public/tickets/updateTicket
Autenticação
- Header:
Authorization: Bearer <token> - Content-Type:
application/json - Middleware:
tolkyAuthMiddleware(injetahostId/hostSlugautomaticamente)
Parâmetros
Obrigatórios
| Parâmetro | Tipo | Descrição |
|---|---|---|
ticketId | string (UUID) | ID único do ticket a ser atualizado |
Campos de Atualização (Opcionais)
| Parâmetro | Tipo | Descrição |
|---|---|---|
subject | string | Assunto do ticket |
description | string | Descrição detalhada do problema |
definitionOfDone | string | Definição de pronto (DOD) |
status | object | Status do ticket |
status.label | string | Nome do status |
status.level | number | Nível numérico do status |
status.tickets_levels_id | string (UUID) | ID do nível (preferencial) |
importance | object | Importância do ticket |
importance.importance_level | number | Nível de importância (1=baixa, 4=urgente) |
importance.importance_label | string | Label da importância |
assignedUser | object | Usuário responsável |
assignedUser.hostPeopleId | string (UUID) | ID do usuário no host |
assignedUser.name | string | Nome do usuário (opcional, para histórico) |
closed | boolean | Status de fechamento do ticket |
Campos de Movimentação (Opcionais)
| Parâmetro | Tipo | Descrição |
|---|---|---|
newLevel | string | UUID | Nome/nível ou ID do nível de destino |
reason | string | Motivo da movimentação (cria evento “Motivo”) |
conversationId | string (UUID) | ID da conversa (para eventos no chat) |
isAutomaticMove | boolean | Indica se é movimentação automática (default: false) |
Contexto/Segurança (Opcionais)
| Parâmetro | Tipo | Descrição |
|---|---|---|
authUserId | string (UUID) | ID do usuário autenticado (para vincular eventos) |
globalData | object | Contexto adicional da requisição |
Regras de Negócio
- Obrigatório:
ticketIddeve ser fornecido - Operação Mínima: Pelo menos uma operação (atualização OU movimentação)
- Ordem de Execução: Se ambas operações forem solicitadas, a atualização é executada primeiro, depois a movimentação
- Permissões: Respeita permissões do host via
tolkyAuthMiddleware - Prioridade de Nível:
status.tickets_levels_idé preferencial para trocar status
Exemplos de Requisição
Apenas Atualização
{
"ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"subject": "Atualizar orçamento",
"description": "Cliente solicitou revisão do escopo",
"importance": {
"importance_level": 3,
"importance_label": "Alta"
},
"assignedUser": {
"hostPeopleId": "4a6b9f6e-0f2f-4e2b-9a77-98b0d64c4d11"
}
}
Apenas Movimentação
{
"ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"newLevel": "3fb2a9f0-5aa3-4f6d-8d37-c2a0b1d7b9a2",
"reason": "Aprovado pelo gerente",
"isAutomaticMove": false
}
Atualização + Movimentação
{
"ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"subject": "Orçamento aprovado",
"newLevel": "Concluído",
"reason": "Entregue ao cliente",
"authUserId": "d7b5d8a9-3f4c-4ed3-9c77-22f577d25f10"
}
Atualização de Status com ID Específico
{
"ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"status": {
"label": "Em Progresso",
"level": 2,
"tickets_levels_id": "3fb2a9f0-5aa3-4f6d-8d37-c2a0b1d7b9a2"
},
"closed": false
}
Resposta de Sucesso
{
"success": true,
"message": "Ticket updated and moved successfully",
"data": {
"ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"operationsPerformed": {
"updated": true,
"moved": true
},
"updateResult": {
"id": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"protocol": "ABCD-1234",
"subject": "Orçamento aprovado",
"description": "Cliente solicitou revisão do escopo",
"status": {
"name": "Em Progresso",
"level": 2,
"color": "#F6AD55",
"isClosed": false
},
"importance": 3,
"importanceColor": "#F6AD55",
"assignedUser": {
"id": "4a6b9f6e-0f2f-4e2b-9a77-98b0d64c4d11",
"name": "João Silva"
}
},
"moveResult": {
"data": {
"ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"previousLevel": {
"name": "Em Progresso",
"level": 2,
"id": "3fb2a9f0-5aa3-4f6d-8d37-c2a0b1d7b9a2"
},
"newLevel": {
"name": "Concluído",
"level": 3,
"id": "4fb2a9f0-5aa3-4f6d-8d37-c2a0b1d7b9a3",
"color": "#68D391",
"external_id": "completed"
},
"updatedTicket": { ...registro completo do ticket... }
}
},
"finalTicketState": { ...estado final do ticket... }
}
}
Códigos de Erro
| Código | Erro | Descrição | Solução |
|---|---|---|---|
400 | MissingTicketId | Ticket ID não fornecido | Incluir ticketId na requisição |
400 | NoOperationSpecified | Nenhuma operação especificada | Fornecer pelo menos um campo para atualizar ou newLevel |
403 | Invalid credentials | Credenciais inválidas | Verificar token de autenticação |
500 | UpdateTicketError | Erro na atualização | Contatar suporte técnico |
500 | MoveTicketError | Erro na movimentação | Contatar suporte técnico |
Exemplo com cURL
curl -X POST "$BASE_URL/api/externalAPIs/public/tickets/updateTicket" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ticketId": "b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a",
"newLevel": "Concluído",
"reason": "Entregue ao cliente"
}'
Exemplo de Integração Completa
class TicketUpdater {
constructor(apiToken, baseUrl) {
this.apiToken = apiToken;
this.baseUrl = baseUrl;
}
async updateTicket(ticketId, updates) {
try {
const response = await fetch(`${this.baseUrl}/api/externalAPIs/public/tickets/updateTicket`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiToken}`
},
body: JSON.stringify({
ticketId,
...updates
})
});
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 atualizar ticket:', error);
throw error;
}
}
// Atualizar apenas campos
async updateFields(ticketId, fields) {
return await this.updateTicket(ticketId, fields);
}
// Mover apenas estágio
async moveToLevel(ticketId, newLevel, reason, isAutomatic = false) {
return await this.updateTicket(ticketId, {
newLevel,
reason,
isAutomaticMove: isAutomatic
});
}
// Atualizar e mover
async updateAndMove(ticketId, fields, newLevel, reason) {
return await this.updateTicket(ticketId, {
...fields,
newLevel,
reason
});
}
// Fechar ticket
async closeTicket(ticketId, reason, authUserId) {
return await this.updateTicket(ticketId, {
closed: true,
newLevel: "Concluído",
reason,
authUserId
});
}
// Atribuir ticket
async assignTicket(ticketId, hostPeopleId, userName) {
return await this.updateTicket(ticketId, {
assignedUser: {
hostPeopleId,
name: userName
}
});
}
}
// Uso da classe
const ticketUpdater = new TicketUpdater('seu_token_aqui', 'https://api.tolky.to');
// Exemplos de uso
async function examples() {
try {
// Atualizar apenas campos
await ticketUpdater.updateFields('b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a', {
subject: 'Novo assunto',
importance: { importance_level: 4, importance_label: 'Urgente' }
});
// Mover apenas estágio
await ticketUpdater.moveToLevel('b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a', 'Concluído', 'Aprovado pelo cliente');
// Atualizar e mover
await ticketUpdater.updateAndMove('b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a',
{ subject: 'Orçamento finalizado' },
'Concluído',
'Entregue ao cliente'
);
// Fechar ticket
await ticketUpdater.closeTicket('b8c9f8c4-0b6a-4b2a-8f8f-0c9d9e2f5a1a', 'Resolvido', 'd7b5d8a9-3f4c-4ed3-9c77-22f577d25f10');
} catch (error) {
console.error('Erro:', error.message);
}
}
Considerações Importantes
Movimentação de Níveis
newLevelaceita:- UUID de
tickets_levels.id(preferido) - Nome/nível resolvido por host (fallback)
- UUID de
status.tickets_levels_idé o caminho preferencial para trocar status
Eventos Automáticos
- Eventos de histórico são criados automaticamente (status, info, motivo se enviado)
- Eventos são vinculados ao
authUserIdquando fornecido - Eventos podem ser escritos no chat via
conversationId
Integração HubSpot
- Se habilitada no avatar/host, a movimentação sincroniza estágio automaticamente
- Sincronização ocorre quando aplicável ao estágio de destino
Importante: Sempre forneça o ticketId válido. Tentativas de atualização com IDs inexistentes resultarão em erro 404.
Dica: Use status.tickets_levels_id para mudanças de status mais precisas, especialmente em integrações automatizadas.
Nota: A movimentação é executada após a atualização quando ambas operações são solicitadas na mesma requisição.