Skip to main content
Endpoint principal para interactuar con el agente. Usa Server-Sent Events (SSE) para enviar la respuesta en tiempo real, token por token.

Request

GET https://api.thaliq.com/api/agent/stream?q={mensaje}

Query Parameters

ParametroRequeridoDescripcion
qSiEl mensaje del usuario (URL-encoded)
conversationIdNoID de conversacion existente. Si se omite o expiro, el backend crea una nueva. Valores reservados (pending, new, null, undefined) son rechazados
agentIdNoOverride del agente. Si se omite, se usa el agente bindeado a la API key (o el default del tenant si no hay binding)
agentTypeNo'general' por defecto
channelNo'platform' | 'widget' | 'sdk' | 'studio' | 'whatsapp' | 'telegram' | 'slack'. Afecta filtrado en stats e inbox
actionResponseNoRespuesta a una accion HITL pendiente (JSON URL-encoded)

Headers

Ver Autenticacion para el detalle completo. Headers comunes:
HeaderRequeridoDescripcion
X-API-KeySiAPI Key del tenant
X-Integration-TypeNowidget o sdk
X-User-IdNoID del usuario final (tracking)
X-Participant-IdNoFingerprint del visitante anonimo
X-MCP-TokensNoJSON {"<serverId>":"<token>"}
AuthorizationNoBearer <jwt> (passthrough MCP)

Eventos SSE

La respuesta es un stream de eventos SSE. Cada evento tiene un event type y data JSON:
event: meta
data: {"conversationId":"conv_abc123"}

event: status
data: {"message":"Pensando..."}

event: content.delta
data: {"delta":"Nuestro "}

event: content.delta
data: {"delta":"horario es "}

event: content.delta
data: {"delta":"de 9am a 6pm."}

event: response.completed
data: {"conversationId":"conv_abc123"}

Tipos de eventos

EventoDescripcionData
metaMetadata inicial de la conversacion (se emite tras resolver/crear el thread). Antes de este evento, no consideres que tenes un conversationId valido{ conversationId }
keepaliveHeartbeat cada 20s para evitar que proxies/CDNs corten la conexion idle{ ts }
statusEstado intermedio del agente (“Pensando…”, “Buscando en documentos…”){ text }
content.deltaFragmento de texto de la respuesta. Se emiten muchos en orden — concatenalos{ delta }
tool.startEl agente comenzo a ejecutar una tool{ tool }
tool.endLa tool termino de ejecutarse{ tool, success, durationMs }
rag.contextChunks RAG recuperados (debug — solo cuando hay docs subidos){ documentsUsed, totalChunks, queryUsed, tokenCount }
actionAccion interactiva pendiente (Human-in-the-Loop). El stream se cierra despues de este evento — para continuar mandar actionResponse en un nuevo request{ type, instructionId, message, options?, fields? }
handoffEscalacion a un humano (la conversacion entra al inbox){ message, agentName?, reason? }
response.completedStream completado. Util para capturar metadata final (messageId para feedback){ message, metadata: { messageId, model, generatedAt }, promptTokens, completionTokens, insights? }
errorError durante el procesamiento. El stream se cierra{ message }

Ejemplo con curl

curl -N -H "X-API-Key: tq_live_xxx" \
  "https://api.thaliq.com/api/agent/stream?q=Hola%20necesito%20ayuda"

Ejemplo con JavaScript

const params = new URLSearchParams({ q: 'Hola, necesito ayuda' });
const response = await fetch(
  `https://api.thaliq.com/api/agent/stream?${params}`,
  {
    headers: {
      'X-API-Key': 'tq_live_xxx',
    },
  }
);

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
  const { value, done } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });

  // Procesar eventos separados por doble newline
  let idx;
  while ((idx = buffer.indexOf('\n\n')) !== -1) {
    const rawEvent = buffer.slice(0, idx);
    buffer = buffer.slice(idx + 2);

    let eventType = 'message';
    const dataLines = [];

    for (const line of rawEvent.split('\n')) {
      if (line.startsWith('event:')) eventType = line.slice(6).trim();
      else if (line.startsWith('data:')) dataLines.push(line.slice(5).trim());
    }

    const data = JSON.parse(dataLines.join('\n'));

    switch (eventType) {
      case 'content.delta':
        process.stdout.write(data.delta); // Mostrar texto progresivamente
        break;
      case 'tool.start':
        console.log(`\n[Tool: ${data.tool}]`);
        break;
      case 'response.completed':
        console.log('\n--- Fin ---');
        break;
    }
  }
}

Ejemplo con EventSource (alternativa)

const params = new URLSearchParams({ q: 'Hola' });
const es = new EventSource(
  `https://api.thaliq.com/api/agent/stream?${params}&apiKey=tq_live_xxx`
);

es.addEventListener('content.delta', (e) => {
  const data = JSON.parse(e.data);
  document.getElementById('response').textContent += data.delta;
});

es.addEventListener('response.completed', () => {
  es.close();
});

es.addEventListener('error', () => {
  es.close();
});
EventSource no soporta custom headers. Para enviar la API Key como header (recomendado), usa fetch con ReadableStream como en el ejemplo anterior.

Respondiendo a acciones interactivas

Cuando recibes un evento action, el stream se cierra. Para responder, envias un nuevo request con el parametro actionResponse:
// Respuesta a un confirm
const actionResponse = JSON.stringify({
  instructionId: 'inst_abc123',
  accepted: true,
});

const params = new URLSearchParams({
  q: 'Quiero agendar una cita', // El mensaje original
  actionResponse,
});

const response = await fetch(
  `https://api.thaliq.com/api/agent/stream?${params}`,
  { headers: { 'X-API-Key': 'tq_live_xxx' } }
);

Tipos de actionResponse

Consent / Confirm:
{ "instructionId": "inst_xxx", "accepted": true }
Select:
{ "instructionId": "inst_xxx", "selectedValue": "opcion_1" }
Form:
{ "instructionId": "inst_xxx", "formValues": { "nombre": "Juan", "email": "juan@email.com" } }