API · conversations

conversations operations in the OpenAPI contract that accept an API key.

Updated:

GET /conversations

Listar conversaciones del inbox (más recientes primero)

Array sin envoltorio; se pagina con limit + offset (F2-03). El panel lo adapta a Page (F3-16). Rol staff (F2-52): solo las conversaciones de clientes con tareas vigentes (o cerradas hace menos de 48 h) en un recurso propio; sin tareas, lista vacía. Los filtros se combinan entre sí (AND) y siempre dentro de ese alcance.

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
modequeryNobot, human, paused
lifecyclequeryNoarray<ConversationLifecycle>Filtro por estado del ciclo de vida (F2-35). Multi-valor (?lifecycle=pending&lifecycle=waiting_team): une los estados con OR. Valor desconocido: 422.
channel_typequeryNoarray<—>Filtro por canal visible (el mismo valor que channel_type de cada conversación). Multi-valor (?channel_type=whatsapp&channel_type=telegram): une los canales con OR. Valor desconocido: 422.
last_message_fromqueryNostring (date-time)Solo conversaciones cuyo último mensaje (last_message_at) es igual o posterior a este instante (ISO 8601 con zona). Sin mensajes no entra en ningún rango.
last_message_toqueryNostring (date-time)Solo conversaciones cuyo último mensaje es anterior a este instante (límite exclusivo, [from, to)).
bot_pausedqueryNobooleantrue: el bot no responde (una persona tomó la conversación, human, o se pausó, paused). false: solo las que atiende el bot.
replied_by_mequeryNobooleantrue: conversaciones donde quien consulta (sesión del panel) mandó al menos un mensaje; false: las demás. Con API key no hay persona: true devuelve una lista vacía.
needs_attentionqueryNobooleantrue: solo las conversaciones que necesitan atención; false: solo las que no (F3-487). Se calcula en la consulta con la misma regla que el campo needs_attention y que el conteo de /conversations/counts, así que paginar con offset recorre exactamente ese número de conversaciones.
limitqueryNointeger default 50
offsetqueryNointeger default 0

Responses

StatusDescription
200OK (array<Conversation>)
defaultError (RFC 9457) (Problem)

GET /conversations/{id}

Detalle de una conversación

Rol staff (F2-52): conversación de un cliente sin tareas suyas ⇒ 404 (no revela que existe).

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
idpathYesstring

Responses

StatusDescription
200OK (Conversation)
defaultError (RFC 9457) (Problem)

PATCH /conversations/{id}

Actualizar etiquetas y/o estado del ciclo de vida de una conversación

contact_action (F3-143) permite release/report_spam/block/unblock solo con sesión owner/manager (contacts:moderate; API key 403). No ejecuta ni confirma tareas retenidas. Parcial: al menos uno de contact_action, tags (reemplaza las etiquetas) o lifecycle (transición manual, F2-35); sin ninguno, 422. Transiciones permitidas: entre pending, waiting_customer, waiting_team hacia cualquiera de ellas, resolved o closed; open solo desde resolved/closed (reabrir); desde resolved también a pending/closed; desde closed solo a open/pending. Otra combinación: 409 lifecycle_transition_not_allowed. Mismo estado = no-op idempotente (sin evento). resolution_reason solo con resolved/closed (422 si no) y se limpia al reabrir. Cada cambio se audita (sin datos personales) y emite conversation.lifecycle_changed. Roles owner/manager/staff; viewer 403. API key: scope messages:write. El ciclo de vida es ortogonal al modo bot/humano. lifecycle: resolved equivale a POST /resolve sobre el último entrante (fija resolved_at, emite conversation.resolved); salir de resolved limpia resolved_at. "Archivar" = closed (sale de la lista principal con ?lifecycle= de los estados activos; "desarchivar" = open). Un mensaje nuevo del cliente reabre una conversación resolved o closed (pasa a pending).

  • Authentication: API key or dashboard session
  • Scopes: messages:write

Parameters

NameInRequiredTypeDescription
idpathYesstring

Request body (required)

  • application/json: object

Responses

StatusDescription
200Conversación actualizada (Conversation)
defaultError (RFC 9457) (Problem)

GET /conversations/{id}/messages

Mensajes de una conversación (cronológico ascendente)

Rol staff (F2-52): conversación de un cliente sin tareas suyas ⇒ 404.

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
idpathYesstring
limitqueryNointeger default 50
beforequeryNostring (date-time)Solo mensajes anteriores a este instante (paginación hacia atrás)

Responses

StatusDescription
200OK (array<Message>)
defaultError (RFC 9457) (Problem)

POST /conversations/{id}/messages

Enviar mensaje manual (pone la conversación en modo humano)

Persiste una salida delivery_status=pending y el takeover en la misma transacción. El worker entrega después del commit; 201 no confirma aceptación del proveedor. Idempotency-Key opcional deduplica 24 h para sesión de panel y Bearer; una misma clave con otro actor, conversación o texto devuelve 422. Un replay devuelve la respuesta original (puede seguir indicando pending); GET messages muestra el estado actual. Un cliente is_test sólo puede usar simulator, nunca una conexión real. Entrega externa at-least-once: sin idempotencia del proveedor existe ventana ambigua. Rol staff (F2-52): solo a clientes con tareas vigentes en un recurso propio; otra conversación ⇒ 404 y no se envía nada. 409 channel_paused si el dueño pausó ese canal a nivel channel (el equipo tampoco envía hasta reanudarlo).

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
idpathYesstring
Idempotency-KeyheaderNostring

Request body (required)

  • application/json: object

Responses

StatusDescription
201Persistido, pendiente de despacho durable (Message)
defaultError (RFC 9457) (Problem)

POST /conversations/{id}/messages/{message_id}/intent

Registrar una intención explícitamente clasificada por el operador

Owner/manager con sesión y CSRF, o API key messages:write. Mensaje entrante real de esta conversación y tenant. Clasificación cerrada e inmutable; mismo valor es replay y distinto devuelve 409. No usa texto LLM, no ejecuta la intención ni modifica estado de reservas.

  • Authentication: API key or dashboard session
  • Scopes: messages:write

Parameters

NameInRequiredTypeDescription
idpathYesstring
message_idpathYesstring (uuid)

Request body (required)

  • application/json: object

Responses

StatusDescription
200Clasificación persistida (o replay) (MessageIntent)
defaultError (RFC 9457) (Problem)

POST /conversations/{id}/mode

Cambiar el modo (takeover / devolver al bot / pausar)

Rol staff (F2-52): solo conversaciones de sus clientes; otra ⇒ 404.

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
idpathYesstring

Request body (required)

  • application/json: object

Responses

StatusDescription
200OK (object)
defaultError (RFC 9457) (Problem)

POST /conversations/{id}/notes

Agregar un aviso de sistema a la conversación (nunca se envía al cliente)

F3-222. Deja un mensaje type=system en el hilo (p. ej. el contexto de un caso de soporte): nace delivery_status=sent, sin destinatario, así que el worker nunca lo despacha por el canal. No cambia el modo (bot/humano) ni el ciclo de vida y no cuenta como respuesta del equipo. Roles owner/manager (sesión con CSRF) o API key con messages:write; tenant desde la credencial; 404 si la conversación no es de este proyecto. Idempotente por contenido: el mismo texto ya presente como aviso en la conversación devuelve ese aviso (sin otro mensaje ni otra auditoría), con cualquier clave o key. Con API key, Idempotency-Key además deduplica 24 h (la misma clave con otro cuerpo da 409). Auditado conversation.system_note (solo el largo del texto).

  • Authentication: API key or dashboard session
  • Scopes: messages:write

Parameters

NameInRequiredTypeDescription
idpathYesstring
Idempotency-KeyheaderNostring

Request body (required)

  • application/json: object

Responses

StatusDescription
201Aviso guardado en el hilo (Message)
defaultError (RFC 9457) (Problem)

POST /conversations/{id}/read

Marcar la conversación como leída

Rol staff (F2-52): solo conversaciones de sus clientes; otra ⇒ 404.

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
idpathYesstring

Responses

StatusDescription
200OK (object)
defaultError (RFC 9457) (Problem)

POST /conversations/{id}/resolve

Resolver explícitamente la conversación leída

Owner/manager con sesión y CSRF, o API key messages:write. Tenant de la credencial. message_id debe ser el último entrante persistido del tenant; snapshot obsoleto devuelve 409. Repetir sobre el mismo mensaje no cambia fecha ni duplica audit/evento. Una nueva entrada real reabre; un replay del webhook no reabre. No cambia el modo ni ejecuta reservas.

  • Authentication: API key or dashboard session
  • Scopes: messages:write

Parameters

NameInRequiredTypeDescription
idpathYesstring

Request body (required)

  • application/json: object

Responses

StatusDescription
200Resuelto (o replay de la misma resolución) (ConversationResolution)
defaultError (RFC 9457) (Problem)

GET /conversations/{id}/summary

Último resumen con IA de la conversación (sin llamar al LLM)

Owner, manager y staff. Devuelve el resumen guardado (summary: null si nunca se generó) y stale: true si llegaron mensajes después. Nunca consume IA. Rol staff (F2-52): conversación de un cliente sin tareas suyas ⇒ 404. Viewer ⇒ 403.

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
idpathYesstring

Responses

StatusDescription
200OK (ConversationSummary)
defaultError (RFC 9457) (Problem)

POST /conversations/{id}/summary

Resumir la conversación con IA (acotado y cacheado)

Owner, manager y staff con sesión de panel y CSRF. Texto de lectura para el equipo: el LLM no decide nada. Pasa por el AI gateway (cuota del proyecto, pausa de IA manual y por spam, freno de ráfaga, registro de uso summary.conversation). Solo se leen los últimos 40 mensajes, con tope de caracteres de entrada y 2048 tokens de salida (incluido razonamiento), con un único reintento de hasta 4096 tokens si el contenido llega vacío; los teléfonos y emails se enmascaran ([tel], [email]) antes y después. El último resumen se guarda con el id del último mensaje considerado: sin mensajes nuevos se devuelve el guardado (cached: true) sin llamar al LLM, aunque la IA esté pausada. Rol staff: fuera de su alcance ⇒ 404. 409 ai_paused (pausa del dueño o auto_spam), 429 ai_limit_reached (cuota) y demás ai_* de admisión, 409 ai_unavailable (key pendiente), 422 conversation_empty (sin texto), 502 ai_provider_unavailable (error del proveedor, detail con tipo/status/motivo seguros) o ai_empty_response (modelo sin texto tras dos intentos).

  • Authentication: API key or dashboard session
  • Scopes: None

Parameters

NameInRequiredTypeDescription
idpathYesstring

Responses

StatusDescription
200Resumen vigente (generado ahora o reutilizado) (ConversationSummary)
defaultError (RFC 9457) (Problem)

GET /conversations/counts

Contadores de conversaciones por estado del ciclo de vida

Cantidad de conversaciones por lifecycle (siempre las seis claves, con 0) y total, para los contadores de la Bandeja. Excluye las sesiones de prueba (is_test), igual que la lista. mode opcional restringe por modo bot/humano. Lectura para cualquier rol; API key: scope messages:read (F2-35).

  • Authentication: API key or dashboard session
  • Scopes: messages:read

Parameters

NameInRequiredTypeDescription
modequeryNobot, human, paused

Responses

StatusDescription
200OK (ConversationLifecycleCounts)
defaultError (RFC 9457) (Problem)

GET /conversations/stream

Avisos en vivo del inbox (SSE)

text/event-stream. Eventos message.received, message.sent y conversation.updated con {event, workspace_id, conversation_id, mode, lifecycle, unread_count, channel_type, message_id?, direction?}. channel_type es null si la conversación ya fue eliminada. Son avisos: el cliente vuelve a pedir la lista y los mensajes. Rol staff (F2-52): solo recibe los avisos de las conversaciones que puede ver en ese momento; el resto se descarta en el servidor.

  • Authentication: API key or dashboard session
  • Scopes: None

Responses

StatusDescription
200Stream abierto
defaultError (RFC 9457) (Problem)