Pular para o conteúdo

Webhooks

O webhook_url do endpoint de Chat recebe a resposta do agente depois que a requisição original já terminou. Ele é um callback por chamada, indicado quando a sua aplicação não deve manter a conexão aberta durante a execução do agente.

  1. Envie webhook_url e não use sync: true em POST /chat/{id}.
  2. A API registra a entrada e responde 202 Accepted com status: "processing" ou status: "debounced".
  3. O agente é executado em background.
  4. Quando existe uma resposta externa não vazia, o SquadOS faz um POST para a URL informada.
Terminal window
curl -X POST https://api.squados.io/v1/chat/API_INBOX_ID \
-H "Authorization: Bearer pk_sua_chave_aqui" \
-H "Content-Type: application/json" \
-d '{
"message": "Qual é o status do pedido 1234?",
"sync": false,
"webhook_url": "https://integracao.exemplo.com/squados/callback",
"metadata": {
"correlation_id": "evt_01J7Y8Q3",
"ticket_id": "TKT-9981"
}
}'

Uma entrada que passa pela fila de agrupamento retorna:

{
"status": "debounced",
"group_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
"conversation_id": "c3d4e5f6-a7b8-9012-cdef-123456789012"
}

Sem agrupamento, a confirmação pode ser somente:

{
"status": "processing",
"conversation_id": "c3d4e5f6-a7b8-9012-cdef-123456789012"
}

O 202 não contém a resposta nem o message_id do assistente. Ele confirma que a entrada foi aceita, não que o callback será entregue.

O callback usa Content-Type: application/json. Uma resposta comum tem este formato:

{
"event": "message.completed",
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
"success": true,
"conversation_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"message_id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
"response": "O pedido 1234 está em separação e será enviado amanhã.",
"model": "provider/model",
"credits_used": 3,
"attachments_processed": 0,
"responding_agent_name": "Atendimento",
"metadata": {
"correlation_id": "evt_01J7Y8Q3",
"ticket_id": "TKT-9981"
},
"timestamp": "2026-09-01T14:32:07.000Z"
}
CampoTipoRegra
eventstringNa resposta normal, message.completed.
agent_idUUIDAgente associado à execução.
successbooleantrue em message.completed.
conversation_idUUIDUse para consultar a conversa e reconciliar o resultado.
message_idUUIDIdentifica a mensagem do agente. Pode faltar em um caminho que não conseguiu persistir uma mensagem externa.
responsestringTexto final entregue ao canal externo.
modelstringModelo efetivamente usado; pode faltar em callbacks de follow-up.
credits_usednumberCréditos da execução; pode faltar em callbacks de follow-up.
attachments_processedintegerQuantidade de anexos da entrada; pode faltar em callbacks de follow-up.
responding_agent_namestringNome do agente que produziu esta resposta.
metadataobjectDados de correlação preservados da entrada; pode faltar quando nada foi enviado.
timestampdate-timeMomento em que o payload foi montado.

O runtime contém uma variante message.error para uma falha interna durante a etapa de entrega, com agent_id, conversation_id, error, metadata e timestamp. Ela não é uma confirmação garantida de toda falha: se o mesmo destino estiver inacessível, o payload de erro também não conseguirá chegar. Reconcilie ausências pelo histórico da conversa.

Com sync: false, mensagens próximas na mesma conversa podem ser agrupadas em uma única execução. O texto e os anexos são combinados em ordem cronológica, mas o callback preserva apenas o primeiro objeto metadata disponível no grupo (first wins).

Use um identificador de correlação estável entre as entradas que podem cair no mesmo grupo. Não dependa de valores diferentes no metadata de cada mensagem agrupada.

Uma transferência entre agentes pode produzir dois callbacks message.completed, nesta ordem:

  1. a mensagem do agente de origem, com pre_transfer: true;
  2. a resposta do agente de destino, sem esse marcador.

Use message_id como chave de idempotência e não trate conversation_id como identificador único de callback.

Um follow-up automático da mesma conversa também pode chegar à URL registrada. Ele usa message.completed e acrescenta:

CampoTipoSignificado
followupbooleanSempre true nessa variante.
followup_attemptintegerNúmero da tentativa lógica do follow-up. Não é tentativa de entrega HTTP.

O destino precisa ser uma URL HTTP ou HTTPS pública com DNS resolvível. O SquadOS bloqueia loopback, redes privadas e reservadas, endpoints de metadata e hostnames locais ou internos. Essa validação acontece durante o processamento assíncrono; por isso, uma URL bloqueada ainda pode receber um 202 inicial e nunca receber o callback.

Use HTTPS. O callback envia somente o header Content-Type: application/json: ele não possui assinatura, Authorization nem cabeçalhos personalizados. Se o receptor exigir autenticação, use um caminho opaco e de alta entropia e valide também um valor de correlação imprevisível no metadata. Não coloque credenciais reutilizadas de outros sistemas nessa URL.

Responda com qualquer status 2xx. Respostas não-2xx, falhas de rede e URLs bloqueadas são registradas como falha; o corpo devolvido pelo receptor é registrado com limite de 5.000 caracteres.

O callback atual faz no máximo uma tentativa de entrega e não possui reenvio automático. Projete o fluxo como at-most-once:

  • persista rapidamente o payload e responda 2xx;
  • deduplique por message_id;
  • não use a chegada do callback como única fonte de verdade;
  • se ele não chegar, consulte GET /conversations/{conversationId}/messages para reconciliar o histórico.

Consulte Chat para o contrato completo da requisição e Conversas para leitura do histórico.