Referencia
Chat
Conversaciones, turnos, streaming e interacciones. Es el corazón de la API.
Listar chats
api.niucore.com/api/v1/chatsScope: chat:read
Devuelve los chats de esta credencial, del más reciente al más antiguo.
Namespace por credencial
Un chat creado desde la aplicación, o por otra credencial del mismo usuario, no aparece acá. En la aplicación pasa lo contrario: los chats de la credencial se ven, se leen y se pueden continuar desde la UI.
Consulta
is_favoritebooleanFiltra por marcados como favoritos.
pageintegerpor defecto 1Página, empezando en 1.
sizeintegerpor defecto 50Elementos por página. Máximo 200.
Devuelve
idstring (uuid)Identificador del chat.
namestring | nullTítulo de la conversación.
is_favoritebooleanMarcado como favorito.
permission_modestringmanual o auto.
model_idinteger | nullModelo por defecto del chat.
created_atstring (date-time)Creación.
updated_atstring (date-time)Última actividad.
curl -sS -X GET 'https://api.niucore.com/api/v1/chats?page=1&size=20' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": [
{
"id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"name": "Soporte — ticket 8842",
"is_favorite": false,
"permission_mode": "auto",
"model_id": 17,
"created_at": "2026-09-01T14:02:11Z",
"updated_at": "2026-09-01T14:09:44Z"
}
],
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77",
"page": 1,
"size": 20,
"total": 1
}
}Crear un chat
api.niucore.com/api/v1/chatsScope: chat:write
Crea un chat vacío y devuelve su id.
Sugerencia
No es obligatorio: enviar un turno a un chat_id que no existe también lo crea. Este endpoint existe para el integrador que necesita el id antes de tener el primer mensaje.
Cuerpo
namestringTítulo. Máximo 200 caracteres.
model_idintegerModelo por defecto. Los ids válidos salen de GET /chat/catalog.
permission_modestringpor defecto manualModo por defecto del chat. Cada turno puede pedir el suyo.
manualauto
curl -sS -X POST 'https://api.niucore.com/api/v1/chats' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Soporte — ticket 8842",
"permission_mode": "auto"
}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"name": "Soporte — ticket 8842",
"is_favorite": false,
"permission_mode": "auto",
"model_id": 17,
"created_at": "2026-09-01T14:02:11Z",
"updated_at": "2026-09-01T14:09:44Z"
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Ver un chat
api.niucore.com/api/v1/chats /{chat_id}Scope: chat:read
Devuelve un chat de la credencial.
Ruta
chat_idstring (uuid)obligatorioIdentificador del chat.
Errores
- 404
api_v1_not_foundEl chat no existe o es de otra credencial. Los dos casos responden igual.
curl -sS -X GET 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"name": "Soporte — ticket 8842",
"is_favorite": false,
"permission_mode": "auto",
"model_id": 17,
"created_at": "2026-09-01T14:02:11Z",
"updated_at": "2026-09-01T14:09:44Z"
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Renombrar o marcar favorito
api.niucore.com/api/v1/chats /{chat_id}Scope: chat:write
Actualiza el nombre y la marca de favorito. El modelo y el modo de permisos no se editan acá: viajan por turno.
Ruta
chat_idstring (uuid)obligatorioIdentificador del chat.
Cuerpo
namestringNuevo título.
is_favoritebooleanMarca o desmarca el favorito.
curl -sS -X PATCH 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Soporte — ticket 8842 (resuelto)",
"is_favorite": true
}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"name": "Soporte — ticket 8842 (resuelto)",
"is_favorite": true,
"permission_mode": "auto",
"model_id": 17,
"created_at": "2026-09-01T14:02:11Z",
"updated_at": "2026-09-01T14:09:44Z"
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Borrar un chat
api.niucore.com/api/v1/chats /{chat_id}Scope: chat:write
Borrado lógico, igual que en la aplicación: el chat desaparece de los dos lados.
Atención
Los mensajes borrados siguen contando para el consumo ya facturado. Borrar una conversación no borra lo que costó.
Ruta
chat_idstring (uuid)obligatorioIdentificador del chat.
curl -sS -X DELETE 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"deleted": true
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Listar mensajes
api.niucore.com/api/v1/chats /{chat_id} /messagesScope: chat:read
Devuelve los turnos del chat en orden cronológico. Cada elemento trae prompt (lo enviado) y content (lo respondido).
Ruta
chat_idstring (uuid)obligatorioIdentificador del chat.
Consulta
pageintegerpor defecto 1Página, empezando en 1.
sizeintegerpor defecto 50Elementos por página. Máximo 200.
Devuelve
idintegerIdentificador del turno.
chat_idstring (uuid)Chat al que pertenece.
rolestringSiempre assistant.
contentstringRespuesta del modelo.
promptstringLo que se envió. Solo en el listado de mensajes.
statusstringcompleted, cancelled, error o pending. En el historial, un turno de la API que cerró en message.cancelled se lee cancelled.
usageobjectConsumo del turno: prompt_tokens, completion_tokens, total_tokens, reasoning_tokens (enteros) más model y provider. Es null si el turno no llegó a consumir nada. La forma es idéntica en el stream, en la respuesta sincrónica, en el replay y acá.
stepsarrayPasos de razonamiento y herramientas ejecutadas: { key, label, label_code, status, timestamp, duration?, detail?, tokens?, tool_calls? }. Informativo — la forma puede crecer, así que leé los campos que te importan e ignorá el resto.
sourcesarrayFragmentos de bibliotecas usados como contexto.
anonymizationobject | nullReemplazos aplicados por el modo incógnito, si la empresa lo tiene activo.
metadataobject | nullEl metadata que mandó el integrador en el turno, devuelto tal cual.
created_atstring (date-time)Fecha de creación.
curl -sS -X GET 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/messages?page=1&size=50' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": [
{
"id": 90211,
"chat_id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"role": "assistant",
"content": "El pedido 8842 se despachó el 28 de agosto y llegó el 1 de septiembre.",
"prompt": "¿Qué pasó con el pedido 8842?",
"status": "completed",
"usage": {
"prompt_tokens": 1840,
"completion_tokens": 96,
"total_tokens": 1936,
"reasoning_tokens": 0,
"provider": "OPENAI",
"model": "gpt-4o"
},
"steps": [],
"sources": [],
"anonymization": null,
"metadata": {
"ticket": "8842"
},
"created_at": "2026-09-01T14:09:44Z"
}
],
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77",
"page": 1,
"size": 50,
"total": 1
}
}Enviar un turno
api.niucore.com/api/v1/chats /{chat_id} /messagesScope: chat:write
Envía un mensaje y bloquea hasta la respuesta completa. Solo admite permission_mode: "auto".
Idempotency-Key obligatorio
Sin el header el request se rechaza con 400 api_v1_idempotency_key_required. Nunca se genera uno por vos: eso convertiría cada reintento en un turno nuevo — y en un cobro nuevo.
Un turno puede durar minutos. El servidor lo corta a los 30 minutos con 504; poné el timeout de tu cliente HTTP por encima de eso o usá el envío por stream.
Con manual el turno se para a pedir permiso, y por este canal no hay forma de contestarle: por eso se rechaza con 409 en vez de dejar al cliente esperando algo que nunca llega. Para modo manual, usá el stream.
Ruta
chat_idstring (uuid)obligatorioIdentificador del chat. Si no existe, se crea con ese id.
Encabezados
Idempotency-KeystringobligatorioIdentificador único del intento. Reintentar con la misma key devuelve el mismo resultado sin reejecutar el turno.
Cuerpo
contentstringobligatorioEl mensaje. Máximo 64.000 caracteres.
model_idintegerModelo a usar en este turno. Sin él, el del chat o el de la empresa.
permission_modestringpor defecto manualEn este endpoint tiene que ser auto.
auto
attachmentsobjectRecursos que el turno adjunta. Cada tipo exige además el scope de lectura de su recurso.
workspace_idsinteger[]Bibliotecas. Exige libraries:read.
file_idsinteger[]Archivos. Exige libraries:read.
skill_idsinteger[]Habilidades. Exige skills:read.
mcp_server_idsinteger[]Conectores. Exige connectors:use.
metadataobjectDatos propios para correlacionar de tu lado. Se devuelven tal cual y no llegan al modelo. Máximo 2048 bytes serializados.
Devuelve
idintegerIdentificador del turno.
chat_idstring (uuid)Chat al que pertenece.
rolestringSiempre assistant.
contentstringRespuesta del modelo.
promptstringLo que se envió. Solo en el listado de mensajes.
statusstringcompleted, cancelled, error o pending. En el historial, un turno de la API que cerró en message.cancelled se lee cancelled.
usageobjectConsumo del turno: prompt_tokens, completion_tokens, total_tokens, reasoning_tokens (enteros) más model y provider. Es null si el turno no llegó a consumir nada. La forma es idéntica en el stream, en la respuesta sincrónica, en el replay y acá.
stepsarrayPasos de razonamiento y herramientas ejecutadas: { key, label, label_code, status, timestamp, duration?, detail?, tokens?, tool_calls? }. Informativo — la forma puede crecer, así que leé los campos que te importan e ignorá el resto.
sourcesarrayFragmentos de bibliotecas usados como contexto.
anonymizationobject | nullReemplazos aplicados por el modo incógnito, si la empresa lo tiene activo.
metadataobject | nullEl metadata que mandó el integrador en el turno, devuelto tal cual.
created_atstring (date-time)Fecha de creación.
Errores
- 400
api_v1_idempotency_key_requiredFalta el headerIdempotency-Key. - 403
api_token_scope_not_allowedSe adjuntó un recurso sin el scope de lectura correspondiente.data.required_scopesdice cuáles faltan. - 409
api_v1_sync_requires_autopermission_modeno esauto. - 409
api_v1_idempotency_conflictLa misma key se usó antes con otro cuerpo. - 409
api_v1_turn_in_progressEl turno de esa key todavía corre. - 409
api_v1_chat_busyEse chat ya tiene un turno en curso, venga de la API o de la aplicación.data.message_ididentifica cuál. - 422
api_v1_content_too_longcontentsupera el máximo. - 422
api_v1_too_many_attachmentsDemasiados adjuntos. - 502
upstream_errorEl turno falló del otro lado. Elmessage_codees el código del turno (upstream_erroru otro que venga del modelo) ydatatraechat_idymessage_id. Es el mismo cuerpo que te devuelve el replay de la key. - 502
interaction_in_auto_modeEl turno pidió una interacción (por ejemplo, conectar un conector) que el envío sincrónico no puede contestar, y se cortó. Usá el stream. - 504
turn_timeoutEl turno superó su tiempo máximo y se cortó.datatraechat_idymessage_id. - 503
api_v1_core_unavailableEl turno terminó pero no se pudo confirmar su guardado (data.code: "persistence_failed"). Consultá el estado con la misma key antes de reintentar. - 409
api_v1_core_unavailableOtra ejecución cerró este turno (data.code: "idempotency_outcome_unknown"). Repetí el request con la misma key para leer el resultado que quedó.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/messages' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8f0a1c72-5c9e-4a1b-8f31-2d0b7c6e4a95" \
-d '{
"content": "Resumí el estado del pedido 8842 y decime si hay reclamos abiertos.",
"permission_mode": "auto",
"attachments": {
"workspace_ids": [
31
]
},
"metadata": {
"ticket": "8842"
}
}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"id": 90212,
"chat_id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"role": "assistant",
"content": "El pedido 8842 se despachó el 28 de agosto…",
"status": "completed",
"usage": {
"prompt_tokens": 2410,
"completion_tokens": 188,
"total_tokens": 2598,
"reasoning_tokens": 0,
"provider": "OPENAI",
"model": "gpt-4o"
},
"steps": [
{
"key": "search_documents",
"label": "Buscando en tus bibliotecas",
"label_code": "step.tool.running",
"status": "completed",
"timestamp": "2026-09-01T14:09:41Z",
"duration": 1240
}
],
"sources": [
{
"workspace_id": 31,
"file_id": 902,
"score": 0.83
}
],
"anonymization": null,
"metadata": {
"ticket": "8842"
}
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Enviar un turno (stream)
api.niucore.com/api/v1/chats /{chat_id} /messages /streamScope: chat:write
Igual que el envío sincrónico, pero devuelve Server-Sent Events a medida que el turno avanza. Es el único camino para permission_mode: "manual".
La respuesta es text/event-stream. Cada evento trae event: y data: con un JSON. El detalle de cada tipo está en Eventos del stream.
Nota
El turno termina igual aunque el cliente se desconecte: el mensaje se persiste y el resultado queda guardado bajo la Idempotency-Key. Volver a enviar la misma key reentrega ese resultado sin reejecutar nada.
Ruta
chat_idstring (uuid)obligatorioIdentificador del chat. Si no existe, se crea.
Encabezados
Idempotency-KeystringobligatorioIdentificador único del intento.
Cuerpo
contentstringobligatorioEl mensaje.
model_idintegerModelo del turno.
permission_modestringpor defecto manualmanual hace que el turno pida permiso antes de ejecutar herramientas.
manualauto
attachmentsobjectIgual que en el envío sincrónico.
metadataobjectDatos propios.
Errores
- 409
api_v1_chat_busyEse chat ya tiene un turno en curso, venga de la API o de la aplicación. - 409
api_v1_idempotency_conflictLa key se usó con otro cuerpo.
curl -sS -N -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/messages/stream' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-H 'Idempotency-Key: 8f0a1c72-5c9e-4a1b-8f31-2d0b7c6e4a95' \
-d '{
"content": "Resumí el estado del pedido 8842.",
"permission_mode": "manual",
"attachments": { "workspace_ids": [31] }
}'event: message.start
data: {"chat_id":"3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3","message_id":90213,"request_id":"9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"}
event: message.delta
data: {"text":"El pedido 8842","replace":false}
event: message.delta
data: {"text":" se despachó el 28 de agosto.","replace":false}
event: message.step
data: {"steps":[{"key":"search_documents","label":"Buscando en tus bibliotecas","label_code":"step.tool.running","status":"completed","timestamp":"2026-09-01T14:09:41Z","duration":1240}]}
event: ping
data: {"ts":1767222015.42}
event: message.completed
data: {"id":90213,"chat_id":"3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3","role":"assistant","content":"El pedido 8842 se despachó el 28 de agosto.","usage":{"prompt_tokens":2410,"completion_tokens":188,"total_tokens":2598,"provider":"OPENAI","model":"gpt-4o"},"steps":[],"sources":[],"anonymization":null,"metadata":{"ticket":"8842"}}Catálogo del chat
api.niucore.com/api/v1/chat /catalogScope: chat:read
Qué puede usar un turno de esta credencial: modelos, bibliotecas, habilidades y conectores, ya recortados por los permisos del usuario y por el alcance de la credencial.
Nota
Los bloques son condicionales por scope: una credencial sin libraries:read no recibe la clave libraries — no la recibe vacía, no la recibe. Una lista vacía se leería como «no hay ninguna», y eso sería falso.
Sugerencia
Los modelos que devuelve son solo los de tipo COMPLETION. Un modelo de embedding nunca aparece acá: mandarlo como model_id produciría un turno que falla del otro lado.
Devuelve
modelsarrayModelos habilitados (id, name, code, type).
permission_modesstring[]Siempre ["manual", "auto"].
librariesarraySolo con libraries:read.
skillsarraySolo con skills:read.
connectorsarraySolo con connectors:use.
curl -sS -X GET 'https://api.niucore.com/api/v1/chat/catalog' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"models": [
{
"id": 17,
"name": "GPT-4o",
"code": "gpt-4o",
"type": "COMPLETION"
},
{
"id": 23,
"name": "Claude Sonnet",
"code": "claude-sonnet-4",
"type": "COMPLETION"
}
],
"permission_modes": [
"manual",
"auto"
],
"libraries": [
{
"id": 31,
"name": "Procedimientos de soporte"
}
],
"skills": [
{
"id": 147,
"name": "Redactar respuesta a cliente"
}
],
"connectors": [
{
"id": 8,
"name": "gmail",
"display_name": "Gmail"
}
]
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Aprobar herramientas
api.niucore.com/api/v1/chats /{chat_id} /actions /approve-toolScope: chat:write
Responde a un evento message.action_required de tipo tool_approval: una decisión por cada herramienta que el turno pidió ejecutar.
Los tool_use_id salen de payload.tools, donde cada entrada es { tool_use_id, name, server, input }. El action_id es el que vino en el evento: es opaco y solo sirve para ese turno y esa credencial.
Atención
Una interacción se resuelve una sola vez y vence a los 110 segundos. Un segundo intento devuelve 409.
Ruta
chat_idstring (uuid)obligatorioEl chat del turno.
Cuerpo
action_idstringobligatorioEl action_id del evento.
decisionsobject[]obligatorioUna decisión por herramienta. Mínimo una.
tool_use_idstringobligatorioId de la herramienta, del payload.
approvedbooleanobligatoriotrue la ejecuta, false la salta.
Errores
- 404
api_v1_action_not_foundLa interacción no existe, venció o no es de esta credencial. - 409
api_v1_action_not_pendingYa se resolvió, otro request la reclamó primero, o su resultado quedó desconocido. No la reintentes. - 409
api_v1_action_result_unknownEl servicio de conversación recibió la decisión y la rechazó (data.upstream_status). La interacción queda cerrada: consultá el turno. - 503
api_v1_service_unavailableLa decisión no llegó a salir (meta.error_details.retry_action: "retry"). La interacción vuelve apending: reintentar es seguro. - 503
api_v1_action_result_unknownLa decisión salió y no hubo respuesta: no se sabe si se aplicó (retry_action: "check_status"). No la reenvíes; seguí el stream o listá los mensajes. - 503
api_v1_interaction_backend_unavailableNo se pueden resolver interacciones ahora. No es un 404: es una indisponibilidad, y reintentar tiene sentido.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/approve-tool' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action_id": "act_9c2f1e7a4b6d",
"decisions": [
{
"tool_use_id": "toolu_01A9f",
"approved": true
},
{
"tool_use_id": "toolu_01B3k",
"approved": false
}
]
}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"action_id": "act_9c2f1e7a4b6d",
"state": "resolved"
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Responder un plan
api.niucore.com/api/v1/chats /{chat_id} /actions /respond-planScope: chat:write
Aprueba o rechaza el plan que propuso el turno (kind: "plan_approval").
Cuándo llega. No hace falta un modo especial: un turno en manual o en auto emite plan_approval cuando el modelo decide llamar a su herramienta de planificación antes de actuar. Pedirlo en el mensaje —«antes de hacer nada proponé un plan de pasos y esperá mi aprobación»— lo hace más probable, pero no lo garantiza: la decisión es del modelo y depende de cuál esté configurado. Tratá esta interacción como una que puede aparecer, no como una que podés forzar. Lo que NO existe en v1 es el permission_mode: "plan" de la aplicación.
El plan viaja en payload.plan: { title, context, steps, notes }, donde cada paso es { step, action, tool? }. tool solo aparece si ese paso va a usar una herramienta.
Ruta
chat_idstring (uuid)obligatorioEl chat del turno.
Cuerpo
action_idstringobligatorioEl action_id del evento.
actionstringobligatorioLa decisión.
approvereject
Errores
- 404
api_v1_action_not_foundLa interacción no existe, venció o no es de esta credencial. - 409
api_v1_action_not_pendingYa se resolvió, otro request la reclamó primero, o su resultado quedó desconocido. No la reintentes. - 409
api_v1_action_result_unknownEl servicio de conversación recibió la decisión y la rechazó (data.upstream_status). La interacción queda cerrada: consultá el turno. - 503
api_v1_service_unavailableLa decisión no llegó a salir (meta.error_details.retry_action: "retry"). La interacción vuelve apending: reintentar es seguro. - 503
api_v1_action_result_unknownLa decisión salió y no hubo respuesta: no se sabe si se aplicó (retry_action: "check_status"). No la reenvíes; seguí el stream o listá los mensajes. - 503
api_v1_interaction_backend_unavailableNo se pueden resolver interacciones ahora. No es un 404: es una indisponibilidad, y reintentar tiene sentido.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/respond-plan' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action_id": "act_4d8b2c0f9e11",
"action": "approve"
}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"action_id": "act_4d8b2c0f9e11",
"state": "resolved"
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Responder una pregunta
api.niucore.com/api/v1/chats /{chat_id} /actions /respond-elicitationScope: chat:write
Contesta la pregunta que hizo el turno (kind: "elicitation"). Es la elicitation del protocolo MCP: la levanta un conector, no una herramienta nativa de NiuCore.
El payload de la interacción es { message, mode, requested_schema }. requested_schema es un JSON Schema y content tiene que ser un objeto plano que lo cumpla: sus propiedades son los campos que el conector pide, no una lista de opciones.
Ruta
chat_idstring (uuid)obligatorioEl chat del turno.
Cuerpo
action_idstringobligatorioEl action_id del evento.
actionstringobligatorioaccept responde, decline se niega, cancel aborta la pregunta.
acceptdeclinecancel
contentobjectLa respuesta. Objeto plano que cumple payload.requested_schema. Obligatorio con action: "accept".
Errores
- 404
api_v1_action_not_foundLa interacción no existe, venció o no es de esta credencial. - 409
api_v1_action_not_pendingYa se resolvió, otro request la reclamó primero, o su resultado quedó desconocido. No la reintentes. - 409
api_v1_action_result_unknownEl servicio de conversación recibió la decisión y la rechazó (data.upstream_status). La interacción queda cerrada: consultá el turno. - 503
api_v1_service_unavailableLa decisión no llegó a salir (meta.error_details.retry_action: "retry"). La interacción vuelve apending: reintentar es seguro. - 503
api_v1_action_result_unknownLa decisión salió y no hubo respuesta: no se sabe si se aplicó (retry_action: "check_status"). No la reenvíes; seguí el stream o listá los mensajes. - 503
api_v1_interaction_backend_unavailableNo se pueden resolver interacciones ahora. No es un 404: es una indisponibilidad, y reintentar tiene sentido.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/respond-elicitation' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action_id": "act_11ff03ac7d52",
"action": "accept",
"content": {
"email": "ada@acme.test"
}
}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"action_id": "act_11ff03ac7d52",
"state": "resolved"
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Cancelar una conexión pendiente
api.niucore.com/api/v1/chats /{chat_id} /actions /cancel-authScope: chat:write
Desbloquea un turno parado en kind: "auth_required" sin conectar nada. El modelo sigue adelante sin esa herramienta.
No hay confirm-auth público
Completar el OAuth de un conector exige un navegador y una persona, y eso pasa en la aplicación. Desde la API solo se puede cancelar, o pedirle al usuario que conecte el servicio en NiuCore.
Ruta
chat_idstring (uuid)obligatorioEl chat del turno.
Cuerpo
action_idstringobligatorioEl action_id del evento.
Errores
- 404
api_v1_action_not_foundLa interacción no existe, venció o no es de esta credencial. - 409
api_v1_action_not_pendingYa se resolvió, otro request la reclamó primero, o su resultado quedó desconocido. No la reintentes. - 409
api_v1_action_result_unknownEl servicio de conversación recibió la decisión y la rechazó (data.upstream_status). La interacción queda cerrada: consultá el turno. - 503
api_v1_service_unavailableLa decisión no llegó a salir (meta.error_details.retry_action: "retry"). La interacción vuelve apending: reintentar es seguro. - 503
api_v1_action_result_unknownLa decisión salió y no hubo respuesta: no se sabe si se aplicó (retry_action: "check_status"). No la reenvíes; seguí el stream o listá los mensajes. - 503
api_v1_interaction_backend_unavailableNo se pueden resolver interacciones ahora. No es un 404: es una indisponibilidad, y reintentar tiene sentido.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/cancel-auth' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action_id": "act_7b1e5f30ca84"
}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"action_id": "act_7b1e5f30ca84",
"state": "resolved"
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}Cancelar el turno
api.niucore.com/api/v1/chats /{chat_id} /actions /cancelScope: chat:write
Corta el turno en curso del chat. Sin action_id cancela el turno vivo, que es lo habitual cuando se decide abortar.
Sugerencia
Es idempotente: cancelar un turno que ya terminó responde 200 igual. Un cliente que reintenta porque no vio la respuesta no tiene por qué distinguir «lo cancelé yo» de «ya estaba cancelado».
El 200 significa que la cancelación se entregó. Si no se pudo entregar recibís 502 y el turno sigue corriendo: reintentá, y mientras tanto seguí leyendo el stream. Un turno cancelado termina con message.cancelled, y el replay de esa Idempotency-Key devuelve status: "cancelled".
Ruta
chat_idstring (uuid)obligatorioEl chat a cancelar.
Cuerpo
action_idstringOpcional. Con él se exige que la interacción sea del turno de esta credencial.
Errores
- 404
api_v1_not_foundEl chat no existe o es de otra credencial. Cancelar no crea el chat, a diferencia de enviar un turno. - 502
api_v1_core_unavailableLa cancelación no se pudo entregar al turno. El turno sigue corriendo: reintentá.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/cancel' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'{
"status": "success",
"message": "Operación exitosa",
"message_code": "api_v1_ok",
"data": {
"chat_id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
"cancelled": true
},
"meta": {
"request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
}
}