Conversaciones y mensajes
Inicia chats, envía mensajes de seguimiento, recibe las respuestas en streaming por WebSocket, compara modelos, aprueba llamadas a herramientas MCP y comparte conversaciones con la API REST.
Una conversación es un hilo de chat: lo mismo que tu equipo ve en Chat History dentro de la aplicación. La inicias con un mensaje, el modelo responde y tú sigues enviando mensajes de seguimiento. Todas las solicitudes de esta página se ejecutan como el usuario propietario de la clave de API, con los mismos accesos, cuotas y reglas del espacio de trabajo que tendría ese usuario en el navegador.
Todas las rutas son relativas a https://api.stickyprompts.com/api/v1. Los cuerpos de las solicitudes son JSON. Los archivos se suben primero mediante los endpoints de archivos y después se referencian por su ID.
Cómo funciona el chat
- Inicia con
POST /conversation(espera la respuesta completa) o conPOST /conversation/stream(devuelve el control al instante y la respuesta llega por el WebSocket). Ambos crean la conversación y envían el primer mensaje en una sola llamada. - Continúa con
POST /conversation/:idoPOST /conversation/:id/stream. - Cambia el modelo, el estilo o el nivel de razonamiento de los turnos siguientes con
PATCH /conversation/:id/model. Los cuerpos de seguimiento no aceptan un modelo: la conversación recuerda su configuración para el «siguiente mensaje». - Lee el historial con
GET /conversation/:id(paginado, del más reciente al más antiguo) y lista las conversaciones conGET /conversation. - Sigue el progreso en directo con el WebSocket
GET /conversation/:id/ws, o consulta periódicamenteGET /conversation/:idy lee elstatusdel mensaje de la IA.
Identificadores. La mayoría de los endpoints aceptan como :id tanto el ID numérico de la conversación como su slug de 8 caracteres. Los endpoints de compartir, eliminar y aprobar, así como los streams de WebSocket y SSE, solo aceptan el ID numérico; cada caso se indica más abajo.
El objeto Message
Lo devuelven los endpoints de envío sin streaming, aparece dentro de GET /conversation/:id y es el data de los eventos message del WebSocket.
{
"ID": 90412,
"CreatedAt": "2026-09-28T09:14:03.512Z",
"UpdatedAt": "2026-09-28T09:14:09.871Z",
"DeletedAt": null,
"conversation_context_id": 5120,
"ai_model_id": 12,
"ai_model": { "ID": 12, "name": "Example Model", "stream_support": true, "...": "..." },
"agent_id": null,
"is_auto_model": false,
"text": "Here are three subject lines for the Northwind Q4 newsletter: ...",
"raw_text": "Here are three subject lines for the Northwind Q4 newsletter: ...",
"parts": [
{ "id": "p1", "type": "text", "static": true, "text_part": { "text": "Here are three ...", "raw_text": "Here are three ..." } }
],
"thinking": null,
"isUser": false,
"error_text": null,
"error_id": null,
"error_code": null,
"mcp_approval_requests": null,
"ai_style": "prompty",
"status": "finished",
"citations": null,
"response_duration_ms": 6210,
"type": "normal",
"attachments": []
}
| Campo | Tipo | Significado |
|---|---|---|
conversation_context_id | uint o null | La conversación a la que pertenece este mensaje. |
ai_model_id, ai_model | uint, objeto | El modelo que generó este mensaje (IA) o que se seleccionó para él (usuario). |
agent_id, agent | uint, objeto | El agente que respondió, si lo hubo. |
is_auto_model | bool | true cuando el enrutamiento automático eligió el modelo. |
prompt_id | uint o null | El prompt guardado que se usó en este mensaje del usuario. |
text | string | Texto del mensaje. En los mensajes de la IA, los marcadores de cita ya vienen renderizados. |
raw_text | string | El texto de la IA sin procesar (solo en las rutas de lectura y de streaming). |
parts | array | Bloques estructurados. type es text, thinking, web_search, web_fetch, code_execution, image_generation o mcp_call, con el objeto *_part correspondiente. static es true cuando no hay nada que desplegar. |
thinking | string o null | Texto de razonamiento de los modelos de razonamiento. |
isUser | bool | true en los mensajes del usuario, false en los de la IA. |
status | string | thinking, generating o finished. |
error_text, error_id, error_code | string o null | Se rellenan cuando la generación falla. error_id es una referencia de soporte de 10 caracteres; error_code es un código legible por máquina para algunos tipos de fallo, como los bloqueos por datos sensibles y los errores de MCP. |
mcp_approval_requests | array | Aprobaciones de herramientas MCP pendientes o ya resueltas. Consulta Aprobaciones de herramientas MCP. |
tools | array | Herramientas habilitadas en este turno. |
citations | array | Citas de la web y de bases de conocimiento: url, file_path, title, info (kb_id, file_id, rangos de páginas y de filas), citation_index y más. |
knowledge_base_ids, world_knowledge | uint[], bool | Las bases de conocimiento consultadas en este turno y si el modelo podía ir más allá de ellas. |
response_duration_ms | int o null | Tiempo de generación. |
type | string | normal o sub_conversation (el contenedor de una comparación de modelos). |
attachments | array | Archivos y transcripciones adjuntos, cada uno con una clave inicial "type": "file" o "type": "transcription". Siempre es un array. |
Estado. thinking significa que la fila del mensaje de la IA ya existe, pero todavía no se ha generado nada; generating, que está llegando salida parcial; finished, que ha terminado. Un mensaje de la IA que ha fallado también queda en finished, con error_text y error_id rellenos, así que comprueba esos campos y no solo status. Los mensajes del usuario siempre están en finished.
Créditos. Todos los campos credits_used son decimales serializados como cadena JSON, por ejemplo "0.4213".
Envío de mensajes
Cuerpo de la solicitud
POST /conversation y POST /conversation/stream aceptan todos los campos siguientes. Los endpoints de seguimiento solo aceptan los marcados con «seguimiento»; el resto se ignora sin avisar. La validación de la solicitud no exige técnicamente ningún campo, pero envía siempre un message y un modelo.
-
messagestring opcional - El mensaje del usuario. Menciona
@<agent-tag>para dirigir el turno a uno de tus agentes. Inicio y seguimiento. -
attachmentsarray opcional - Elementos
{ "id": uint, "type": "file" | "transcription", "temp": bool }. Archivos subidos o transcripciones terminadas. Contemp: true, el adjunto se usa solo en este turno y no queda registrado en el mensaje. Inicio y seguimiento. -
knowledge_base_idsuint[] opcional - Bases de conocimiento de las que se obtiene contexto en este turno. Inicio y seguimiento.
-
knowledge_base_limit_node_idsuint[] opcional - Limita la recuperación a estas carpetas o archivos de la base de conocimiento. Inicio y seguimiento.
-
world_knowledgebool opcional por defectofalse false: responde solo a partir de la base de conocimiento.true: la base de conocimiento es la fuente principal, pero el modelo también puede usar la búsqueda web y su propio conocimiento. Inicio y seguimiento.-
flash_modebool opcional - Solicita el nivel de servicio prioritario del proveedor. Solo tiene efecto en los modelos que lo admiten. Inicio y seguimiento.
-
toolsarray opcional - Elementos
{ "name", "use", "mcp_tool_id"? }. Consulta Herramientas. Inicio y seguimiento. -
ai_model_iduint opcional - Modelo que se usará, obtenido de
GET /ai_model. Se ignora si se defineauto_model_type. Solo al inicio. -
auto_model_typestring opcional best,balancedocheapest. El enrutamiento automático elige el mejor modelo para cada mensaje y tiene prioridad sobreai_model_id. Solo al inicio.-
ai_stylestring opcional por defectoprompty - Estilo de respuesta: el valor
tonede un estilo de IA. Solo al inicio. -
reasoning_effortstring opcional - Nivel de razonamiento para los modelos de razonamiento. Un valor no admitido se sustituye por el predeterminado del modelo; en los modelos sin razonamiento se guarda null. Solo al inicio.
-
agent_iduint opcional - Inicia un chat con un agente: en cada turno se usan el modelo, el prompt de sistema, las herramientas, los servidores MCP, las bases de conocimiento y los archivos del agente. El agente debe ser tuyo. Solo al inicio.
-
invited_agent_idsuint[] opcional - Agentes tuyos que se pueden mencionar (
@mentioned) en esta conversación. Se ignora cuando se defineagent_id. Solo al inicio. -
team_iduint opcional - Crea una conversación de equipo (el equipo obtiene acceso
chat_contribute). Consulta Cuándo responde la IA. Solo al inicio. -
X-Project-IDinteger en header opcional - Solo al inicio. Archiva la conversación en este proyecto. Si el cuerpo no incluye un modelo, se usa el modelo predeterminado del proyecto. En cada turno, los archivos del proyecto se añaden al contexto. El campo
project_iddel cuerpo existe, pero no se lee: usa este header.
Selección del modelo. Primero cuenta auto_model_type, después ai_model_id y, por último, el modelo predeterminado del proyecto (con X-Project-ID). Si no se aplica ninguno, la conversación se crea igualmente, pero el envío falla con 503 {"error":"no AI model is selected, try reselecting model"}, así que al iniciar envía siempre un modelo o un tipo automático. No existe ningún ID de modelo literal "auto". Los chats con agentes y las menciones con @agent usan el modelo del agente (estilo prompty, sin nivel de razonamiento). El modelo debe estar permitido por las reglas de acceso a modelos y de residencia de datos de tu espacio de trabajo; si no, el envío falla con 503.
Herramientas
Cada entrada es { "name": ..., "use": true | false }. Nombres: web_search, image_generation, video_generation, speech_generation, music_generation, remote_mcp.
- Una herramienta solo llega al modelo si este la incluye entre sus capacidades
tools. Si no, se ignora sin avisar. remote_mcpnecesita además"mcp_tool_id": <id>, el ID de uno de tus servidores MCP remotos configurados. Añade una entrada por servidor.- Selección automática de herramientas. En los modelos que admiten herramientas, un pequeño clasificador puede activar
web_searcheimage_generation(y la ejecución de código) según el mensaje, aunque no lo hayas pedido. Si envías una entrada para una herramienta, aunque sea{"name":"web_search","use":false}, el clasificador ya no la añade. La ejecución de código la decide únicamente el clasificador.
POST /conversation
/api/v1/conversation Crea una conversación, envía el primer mensaje y espera la respuesta completa de la IA, incluidas las llamadas a herramientas. La respuesta es el mensaje terminado de la IA; el ID de la nueva conversación es su conversation_context_id. La conversación recibe un nombre automático después del primer intercambio. Acepta el cuerpo de la solicitud descrito arriba y, de forma opcional, el header X-Project-ID.
curl -X POST https://api.stickyprompts.com/api/v1/conversation \
-H "Authorization: Bearer $STICKY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Draft three subject lines for the Northwind Q4 newsletter.",
"ai_model_id": 12,
"ai_style": "prompty",
"tools": [{ "name": "web_search", "use": false }]
}'import os, requests
r = requests.post(
"https://api.stickyprompts.com/api/v1/conversation",
headers={"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"},
json={
"message": "Draft three subject lines for the Northwind Q4 newsletter.",
"ai_model_id": 12,
"ai_style": "prompty",
"tools": [{"name": "web_search", "use": False}],
},
timeout=300,
)
r.raise_for_status()
reply = r.json()
if reply.get("error_id"):
print("Failed:", reply["error_text"], reply["error_id"])
else:
print(reply["conversation_context_id"], reply["text"])const res = await fetch("https://api.stickyprompts.com/api/v1/conversation", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.STICKY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
message: "Draft three subject lines for the Northwind Q4 newsletter.",
ai_model_id: 12,
ai_style: "prompty",
tools: [{ name: "web_search", use: false }],
}),
});
const reply = await res.json();
console.log(reply.conversation_context_id, reply.error_id ?? reply.text);Respuesta. 200 con el mensaje de la IA (consulta el objeto Message). Cuando la IA no debe responder (una conversación de equipo con varios miembros y sin mención a @ai ni a ningún agente), el cuerpo es 200 {"conversation_context_id": 5120}.
Errores
| Estado | Cuerpo | Cuándo |
|---|---|---|
400 | {"error": "..."} | JSON mal formado. |
400 | {"error": "...", "error_code": "..."} | Bloqueado por las reglas de datos sensibles de tu espacio de trabajo, o error de un servidor MCP. Cuando la IA no responde, un bloqueo por datos sensibles usa la clave code en lugar de error_code. |
400 | {"error": "Knowledge base not found"} | Base de conocimiento desconocida. |
429 | {"error": "Quota exceeded", "reason": "..."} | Se comprueba antes de crear nada. reason es credit_count, user_count, subscription, trial_expired o unknown. |
503 | {"error": "could not create conversation"} | Por ejemplo, un agent_id que no es tuyo o un team_id desconocido (un fallo al buscar el equipo también puede aparecer como 500). |
503 | {"error": "<message>"} | Cualquier otro fallo: ningún modelo seleccionado, modelo restringido, error del proveedor. |
Si el proveedor falla a mitad de la generación, el mensaje de la IA se guarda igualmente con error_text y error_id, y POST /conversation/:id/retry puede volver a ejecutarlo.
POST /conversation/stream
/api/v1/conversation/stream Mismos headers y cuerpo que POST /conversation, pero responde en cuanto se guarda el mensaje del usuario. La generación continúa en segundo plano y la respuesta llega por el WebSocket o mediante sondeo (polling).
{ "conversation_context_id": 5120 }
Los errores detectados antes de guardar el mensaje del usuario (cuota 429, agente no válido, ningún modelo seleccionado, modelo restringido, bloqueo por datos sensibles) se siguen devolviendo de forma síncrona, con los mismos formatos de arriba. Los errores posteriores al 200 (selección de modelo o de herramientas, obtención de la base de conocimiento, error del proveedor) solo se notifican como evento error_message del WebSocket y quedan guardados en un mensaje de la IA con error_text y error_id.
Cómo obtener la respuesta
- WebSocket (recomendado). Conéctate a
GET /conversation/{conversation_context_id}/ws. Los eventos emitidos antes de que te conectes se guardan en búfer y se reenvían al primer cliente, así que si te conectas justo después del200no pierdes nada. - Sondeo. Llama a
GET /conversation/:id?page=1&size=2y lee el mensaje más reciente de la IA (isUser: false, el primero de la lista, ya que el orden va del más reciente al más antiguo). El mensaje de la IA se crea constatus: "thinking"y se guarda con cada fragmento, así que verásgeneratingcon untextcada vez más largo y, al final,finished. Detente enfinishedy compruebaerror_id. Justo después del200, puede que el mensaje de la IA aún no exista; si el mensaje más reciente sigue siendo el tuyo, la generación todavía no ha empezado.
El streaming solo es en tiempo real en los modelos con stream_support: true. En los demás, la respuesta aparece de una sola vez cuando está terminada.
POST /conversation/:id
/api/v1/conversation/:id Envía un mensaje de seguimiento y espera la respuesta de la IA. El modelo, el estilo y el nivel de razonamiento salen de la configuración next_message_* de la conversación; cámbiala antes con PATCH /conversation/:id/model.
-
idstring en path obligatorio - ID o slug de la conversación.
-
messagestring opcional - El texto de seguimiento.
-
attachmentsarray opcional - Como en el cuerpo de la solicitud.
-
knowledge_base_idsuint[] opcional - Bases de conocimiento para este turno.
-
knowledge_base_limit_node_idsuint[] opcional - Limita la recuperación a estos nodos.
-
world_knowledgebool opcional - Permite usar conocimiento más allá de la base de conocimiento.
-
flash_modebool opcional - Nivel de servicio prioritario, donde esté disponible.
-
toolsarray opcional - Herramientas para este turno.
curl -X POST https://api.stickyprompts.com/api/v1/conversation/5120 \
-H "Authorization: Bearer $STICKY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Make the second one shorter." }'
Respuesta. Igual que en POST /conversation: 200 con el mensaje de la IA, o 200 {"conversation_context_id": ...} cuando la IA no responde. Si la conversación tiene una comparación de modelos activa, el mensaje se envía en paralelo a todos los hilos y la respuesta es un array JSON de mensajes de la IA, uno por hilo.
Errores. Los mismos que en POST /conversation, más 404 {"error":"Conversation not found"}. Solo pueden enviar mensajes el propietario y los usuarios o equipos con chat_contribute; cualquier otra persona recibe 503 {"error":"you are not allowed to send messages in this conversation"}.
POST /conversation/:id/stream
/api/v1/conversation/:id/stream Igual que POST /conversation/:id, pero devuelve 200 {"conversation_context_id": <id>} de inmediato. Sigue el progreso por el WebSocket o mediante sondeo, como con POST /conversation/stream. Con una comparación de modelos activa, todos los hilos se transmiten por el WebSocket de la conversación principal.
-
idstring en path obligatorio - ID o slug de la conversación.
Cuándo responde la IA
La IA responde a un mensaje cuando se cumple cualquiera de estas condiciones:
- solo un usuario tiene acceso de colaboración a la conversación (el caso normal, que incluye todas las conversaciones creadas con una clave de API y sin
team_id); - el texto contiene
@ai(distingue entre mayúsculas y minúsculas); - es un chat con un agente;
- el texto menciona (
@mentions) la etiqueta de un agente invitado a la conversación.
En caso contrario, el mensaje se guarda como un mensaje normal del usuario, visible para los demás participantes, y el endpoint devuelve 200 {"conversation_context_id": <id>} sin llamar a ningún modelo, incluso en los endpoints sin streaming.
Agentes en una conversación
- Si indicas
agent_idal crear la conversación, esta se convierte en un chat con un agente. Su modelo no se puede cambiar después. - En una conversación de un solo usuario,
@tagdirige ese turno a tu propio agente con esa etiqueta o a un agente compartido contigo (si hay conflicto de etiquetas, tienen prioridad tus agentes). En una conversación con varios usuarios, solo se puede mencionar a los agentes invitados coninvited_agent_idso conPOST /conversation/:id/agents. - El agente que responde queda registrado en el mensaje de la IA (
agent_id,agent).
Streaming
GET /conversation/:id/ws
/api/v1/conversation/:id/ws Un WebSocket que envía cada actualización de la conversación. Conéctate a wss://api.stickyprompts.com/api/v1/conversation/5120/ws y envía el header Authorization: Bearer STICKY-API-... en la solicitud de upgrade. Los objetos WebSocket del navegador no pueden definir headers, así que esta opción es para clientes del lado del servidor. El servidor ignora todo lo que envíes; solo lee para detectar el cierre.
-
idinteger en path obligatorio - El ID numérico de la conversación. Con un slug te conectas a otro stream distinto y vacío.
Todas las tramas son tramas de texto JSON con la forma {"type": <string>, "data": <payload>}:
type | data | Cuándo |
|---|---|---|
message | Message (instantánea completa) | Un mensaje nuevo de otro participante y cada actualización de un mensaje de la IA durante la generación. text, parts y thinking contienen el contenido acumulado hasta el momento, no un delta: sustituye tu copia según data.ID. status pasa por thinking, generating y finished. |
ai_message_end | ninguno (la clave no aparece) | La generación ha terminado, con éxito o sin él. Cierra el turno. |
error_message | Message con error_text, error_id, error_code opcional y status: "finished" | Ha fallado la generación o la preparación. Trátalo como el final del turno: tras los fallos de preparación suele llegar un ai_message_end, pero no está garantizado tras errores del proveedor a mitad de la generación. |
ai_model_change | { "ai_model_id", "ai_style", "auto_model_type", "reasoning_effort" } | Alguien ha llamado a PATCH /conversation/:id/model. |
run_data | Objeto RunHistory | Solo en los turnos que proceden de la ejecución de un prompt guardado, junto con los eventos message. Consulta Prompts y ejecuciones. |
{"type":"message","data":{"ID":90412,"isUser":false,"status":"generating","text":"Here are","...":"..."}}
{"type":"message","data":{"ID":90412,"isUser":false,"status":"generating","text":"Here are three options","...":"..."}}
{"type":"message","data":{"ID":90412,"isUser":false,"status":"finished","text":"Here are three options for ...","response_duration_ms":6210,"...":"..."}}
{"type":"ai_message_end"}
- Tus propios mensajes de usuario no se reenvían a tu conexión. La clave actúa en nombre de su propietario, así que un cliente que usa la clave solo ve los mensajes de la IA y los de otras personas.
- Mientras no hay ningún cliente conectado, los eventos se guardan en búfer, se reenvían a la siguiente conexión y después se borran. Un cliente que se conecta mucho después de un turno puede recibir primero eventos obsoletos de ese turno: ignora los mensajes cuyo
IDya tengas en estado terminado. - Los streams residen en la memoria del servidor de la API. Si te conectas y no recibes nada de un turno que sabes que está en curso, recurre al sondeo de
GET /conversation/:id.
# 1. Start the turn without waiting
curl -X POST https://api.stickyprompts.com/api/v1/conversation/stream \
-H "Authorization: Bearer $STICKY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Summarise last week for the Northwind team.", "auto_model_type": "balanced" }'
# -> {"conversation_context_id":5120}
# 2. cURL cannot hold a WebSocket open; poll the newest messages instead
curl "https://api.stickyprompts.com/api/v1/conversation/5120?page=1&size=2" \
-H "Authorization: Bearer $STICKY_API_KEY"import asyncio, json, os, requests, websockets
KEY = os.environ["STICKY_API_KEY"]
BASE = "https://api.stickyprompts.com/api/v1"
start = requests.post(
f"{BASE}/conversation/stream",
headers={"Authorization": f"Bearer {KEY}"},
json={"message": "Summarise last week for the Northwind team.", "auto_model_type": "balanced"},
).json()
cid = start["conversation_context_id"]
async def listen():
url = f"wss://api.stickyprompts.com/api/v1/conversation/{cid}/ws"
async with websockets.connect(url, additional_headers={"Authorization": f"Bearer {KEY}"}) as ws:
async for frame in ws:
event = json.loads(frame)
if event["type"] == "message" and not event["data"]["isUser"]:
print(event["data"]["status"], len(event["data"]["text"]))
elif event["type"] == "error_message":
print("Failed:", event["data"]["error_text"], event["data"]["error_id"])
break
elif event["type"] == "ai_message_end":
break
asyncio.run(listen())import WebSocket from "ws"; // Node: browsers cannot send the Authorization header
const KEY = process.env.STICKY_API_KEY;
const BASE = "https://api.stickyprompts.com/api/v1";
const { conversation_context_id: cid } = await fetch(`${BASE}/conversation/stream`, {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ message: "Summarise last week for the Northwind team.", auto_model_type: "balanced" }),
}).then((r) => r.json());
const ws = new WebSocket(`wss://api.stickyprompts.com/api/v1/conversation/${cid}/ws`, {
headers: { Authorization: `Bearer ${KEY}` },
});
ws.on("message", (raw) => {
const { type, data } = JSON.parse(raw);
if (type === "message" && !data.isUser) console.log(data.status, data.text.length);
if (type === "error_message") { console.error(data.error_text, data.error_id); ws.close(); }
if (type === "ai_message_end") ws.close();
});GET /conversation/:id/stream
/api/v1/conversation/:id/stream Un endpoint heredado de Server-Sent Events. Usa el WebSocket o el sondeo en su lugar. En el código actual, la ruta de envío de la conversación solo escribe en el WebSocket, así que este stream solo muestra eventos error_message y run_data en caso de errores de ejecución de prompts y, por lo demás, permanece abierto sin enviar contenido de los mensajes.
-
idinteger en path obligatorio - ID numérico de la conversación.
Devuelve 404 {"error":"Stream not found"} cuando el servidor no tiene ningún stream en memoria para la conversación. En caso contrario, responde con Content-Type: text/event-stream y tramas event:<name>\ndata:<json>\n\n, donde <name> es message, error_message (array de {run_id, error_id, error_text, model_name}), run_data (array de RunHistory) o close (data: Stream closed).
Lectura de conversaciones
GET /conversation/:id
/api/v1/conversation/:id Devuelve una conversación con una página de sus mensajes, del más reciente al más antiguo. Los metadatos de paginación están en los headers de respuesta X-Total-Count (total de mensajes), X-Page y X-Page-Size.
-
idstring en path obligatorio - ID o slug de la conversación, o su slug público de compartición.
-
pageinteger en query opcional por defecto1 - Número de página.
-
sizeinteger en query opcional por defecto10 - Mensajes por página.
Acceso. El propietario; los usuarios con chat_view o chat_contribute porque se les ha compartido; o, cuando :id es el slug público de una conversación compartida, quien permita el tipo de compartición (public: cualquiera; internal: cualquier usuario con sesión iniciada; workspace: los miembros del espacio de trabajo del propietario).
{
"credits_used": "0.4213",
"conversation_context_id": 5120,
"conversation_context_name": "Q4 newsletter subject lines",
"conversation_context_slug": "aB3dE5gH",
"expensive_warning_threshold": 1000,
"public_slug": null,
"share_type": "",
"is_public": false,
"user_name": "John Smith",
"messages": [
{ "ID": 90412, "isUser": false, "status": "finished", "text": "Here are three options ...", "...": "..." },
{ "ID": 90411, "isUser": true, "status": "finished", "text": "Draft three subject lines ...", "...": "..." }
],
"next_message_ai_model_id": 12,
"next_message_ai_model_style": "prompty",
"next_message_auto_model_type": null,
"next_message_reasoning_effort": null,
"has_sub_conversations": false,
"unsupported_files": null,
"current_user_permission": "chat_contribute",
"owner_id": 77,
"user_count": 1,
"team_shares": null,
"agent_id": null,
"invited_agents": [],
"is_agent_chat": false
}
| Campo | Significado |
|---|---|
credits_used | Créditos de toda la conversación, incluidos los hilos de comparación (cadena decimal). |
messages | Esta página de mensajes, del más reciente al más antiguo. Los mensajes de la IA llevan las citas renderizadas en text y el original en raw_text. |
next_message_ai_model_id, next_message_ai_model | El modelo que usará el siguiente turno. Si no hay ninguno, se usa el del último mensaje de la IA. |
next_message_ai_model_style | Estilo del siguiente turno. Atención: la clave no coincide con next_message_ai_style del objeto de conversación. |
next_message_auto_model_type | best, balanced o cheapest cuando hay enrutamiento automático. |
forked_from_conversation_id, _slug, _name | Se rellenan en las bifurcaciones (forks). |
has_sub_conversations | Existe una comparación de modelos. |
unsupported_files | Archivos adjuntados anteriormente que el siguiente modelo no puede leer. |
current_user_permission | chat_contribute para el propietario; para los demás, su acceso más alto: chat_view, chat_contribute o none. |
team_shares | {team_id, team, access_type} por cada equipo con el que se comparte la conversación. |
Errores. 403 {"error":"You are not allowed to access this conversation"}, 404 {"error":"Conversation not found"}.
GET /conversation
/api/v1/conversation Lista tus conversaciones de chat, empezando por la de actividad más reciente. Solo aparecen las conversaciones de chat interactivas con al menos un mensaje.
-
pageinteger en query opcional por defecto1 - Número de página. Los totales están en los headers
X-Total-Count,X-PageyX-Page-Size. -
sizeinteger en query opcional por defecto10 - Elementos por página.
-
searchstring en query opcional - Busca la subcadena en el texto de cualquier mensaje o en el nombre de la conversación.
-
agent_iduint en query opcional - Lista los chats de este agente. Sin este parámetro, se excluyen los chats con agentes.
-
team_iduint en query opcional - Lista las conversaciones compartidas con este equipo con
chat_contribute. Sin este parámetro, obtienes las conversaciones de las que eres propietario y que no son conversaciones de equipo. -
X-Project-IDinteger en header opcional - Solo las conversaciones de este proyecto.
Respuesta. 200 con un array de objetos de conversación (si no hay ninguno, []). Cada uno incluye precargados user y project, además de message_count, credits_used y, en messages, solo el último mensaje (con attachments vacío). Atención a las claves en camelCase publicSlug, isPublic, userId, projectId, runId, isInteractive y forkedFromConversationId, que conviven con las de snake_case.
[
{
"ID": 5120, "CreatedAt": "2026-09-28T09:13:58Z", "UpdatedAt": "2026-09-28T09:14:10Z", "DeletedAt": null,
"slug": "aB3dE5gH", "publicSlug": null, "isPublic": false, "share_type": "",
"userId": 77, "user": { "ID": 77, "first_name": "John", "last_name": "Smith", "...": "..." },
"next_message_ai_model_id": 12, "next_message_ai_style": "prompty",
"next_message_auto_model_type": null, "next_message_reasoning_effort": null,
"projectId": null, "project": null, "agent_id": null,
"name": "Q4 newsletter subject lines", "source": "chat",
"messages": [ { "ID": 90412, "isUser": false, "text": "Here are three options ...", "...": "..." } ],
"isInteractive": true, "expensive_warning_threshold": 1000,
"forkedFromConversationId": null,
"message_count": 2, "credits_used": "0.4213"
}
]
GET /conversation/:id/used_prompts
/api/v1/conversation/:id/used_prompts Devuelve los distintos prompts guardados que se han ejecutado en esta conversación, incluidos los hilos de comparación: un array de { "id", "name", "slug", "ai_model_id", "user_id" }, o []. El orden no está definido.
-
idstring en path obligatorio - ID o slug de la conversación.
Gestión de conversaciones
PATCH /conversation/:id
/api/v1/conversation/:id Cambia el nombre de una conversación y la sube al principio de la lista. Solo el propietario.
-
idstring en path obligatorio - ID o slug de la conversación.
-
namestring obligatorio - El nuevo nombre. Si está vacío o falta, se devuelve
400.
Respuesta. 200 con el objeto de conversación. Errores. 403 {"error":"You are not allowed to edit this conversation"}.
PATCH /conversation/:id/model
/api/v1/conversation/:id/model Define el modelo, el estilo y el nivel de razonamiento de los turnos siguientes. Pueden usarlo el propietario y los usuarios con chat_contribute. También emite un evento ai_model_change por el WebSocket.
-
idstring en path obligatorio - ID o slug de la conversación.
-
ai_model_iduint opcional - Modelo para los turnos siguientes. Si no existe,
400 {"error":"AI model not found"}. -
ai_stylestring opcional - Estilo para los turnos siguientes.
-
auto_model_typestring opcional best,balanced,cheapesto null. Siempre se escribe: si lo omites o envías null, se desactiva el enrutamiento automático. Envíalo en cada llamada para mantenerlo activo.-
reasoning_effortstring opcional - Se ajusta a los niveles que admite el modelo nuevo o el actual.
Respuesta. 200 {"message":"Model changed successfully"}. Errores. 400 {"error":"Cannot change model for agent conversations"}, 403 si no tienes acceso.
POST /conversation/:id/fork
/api/v1/conversation/:id/fork Crea una conversación nueva llamada "Forked from <name>" con copias de todos los mensajes hasta message_id inclusive. Se copian los adjuntos, las herramientas y los registros de aprobación de MCP, y se conservan el modelo, el estilo y la configuración de razonamiento. Debes ser el propietario de la conversación de origen o esta debe estar compartida; si no, recibes 403.
-
idstring en path obligatorio - ID o slug de la conversación de origen.
-
message_iduint obligatorio - El último mensaje que se copia. Debe ser un mensaje
normalde esta conversación o de uno de sus hilos de comparación (si no,404o400).
Respuesta. 200 con una respuesta de conversación reducida: conversation_context_id, conversation_context_name, conversation_context_slug, public_slug, is_public, user_name, messages (aquí, del más antiguo al más reciente) y credits_used: "0". Las demás claves llevan su valor cero.
DELETE /conversation/:id
/api/v1/conversation/:id Elimina de forma lógica (soft delete) la conversación y sus mensajes, y oculta sus ejecuciones de prompts del historial de ejecuciones. Solo el propietario.
-
idinteger en path obligatorio - ID numérico de la conversación.
curl -X DELETE https://api.stickyprompts.com/api/v1/conversation/5120 \
-H "Authorization: Bearer $STICKY_API_KEY"
Respuesta. 200 {"message":"Conversation deleted successfully"}. Errores. 404 {"error":"Conversation not found or you do not have permission to delete it"}.
POST /conversation/:id/retry
/api/v1/conversation/:id/retry Vuelve a ejecutar el último turno cuando el mensaje más reciente de la IA terminó con un error. El mensaje fallido se regenera en su sitio (mismo ID) con el modelo y el estilo actuales de la conversación, o con los del agente. Solo el propietario. Sin cuerpo.
-
idstring en path obligatorio - ID o slug de la conversación.
Respuesta. 200 con:
- en un turno de chat normal, un Message. En los modelos con
stream_support: true, la llamada responde de inmediato con el mensaje enstatus: "thinking"y el contenido llega por el WebSocket o mediante sondeo; en los demás modelos, devuelve el mensaje terminado; - en un turno que procede de un prompt guardado, un array de objetos RunHistory.
Errores. 400 {"error":"Last AI message does not have an error"}, 400 {"error":"No user message found in this conversation"}, 403, 500 {"error":"..."}.
POST /conversation/:id/snooze-expensive-warning
/api/v1/conversation/:id/snooze-expensive-warning Cuando el credits_used de una conversación supera su expensive_warning_threshold (1000 de forma predeterminada), la aplicación web muestra un aviso de uso. Esta llamada duplica el umbral hasta dejarlo por encima del uso actual. Solo el propietario.
-
idstring en path obligatorio - ID o slug de la conversación.
Respuesta. 200 con el objeto de conversación y su nuevo expensive_warning_threshold. Errores. 400 si el uso sigue por debajo del umbral.
POST /conversation/:id/agents
/api/v1/conversation/:id/agents Invita a uno de tus agentes a la conversación para que se le pueda mencionar (@mentioned). Solo el propietario; no se permite en los chats con agentes (400).
-
idstring en path obligatorio - ID o slug de la conversación.
-
agent_iduint obligatorio - Un agente del que eres propietario.
Respuesta. 200 {"message":"Agent invited successfully"}. Errores. 404 {"error":"Agent not found or not owned by user"}, 403.
DELETE /conversation/:id/agents/:agentId
/api/v1/conversation/:id/agents/:agentId Quita un agente invitado. Solo el propietario.
-
idstring en path obligatorio - ID o slug de la conversación.
-
agentIdinteger en path obligatorio - ID numérico del agente.
Respuesta. 200 {"message":"Agent removed successfully"}. Errores. 400 {"error":"Invalid agent ID"}, 404.
Aprobaciones de herramientas MCP
Esto se aplica cuando un turno usa un servidor MCP remoto (una herramienta remote_mcp o un agente con servidores MCP) cuya configuración tiene require_approval: true y el modelo funciona con el protocolo OpenAI Responses, la única vía que genera aprobaciones. Las ejecuciones de flujos de trabajo siempre se aprueban automáticamente.
- El modelo pide llamar a una herramienta MCP. La generación se detiene y el mensaje de la IA recibe en
mcp_approval_requestsuna entrada por cada llamada solicitada. En la ruta de streaming, además, se añade al texto del mensaje el textoApproval required for action: <name>con la etiqueta del servidor y los argumentos. - Las claves de cada entrada son nombres de campo de Go (sin etiquetas JSON).
Approved: nullsignifica que está pendiente;trueofalse, que ya se ha decidido.
{
"ID": 311, "CreatedAt": "2026-09-28T09:20:01Z", "UpdatedAt": "2026-09-28T09:20:01Z", "DeletedAt": null,
"ApprovalRequestID": "mcpr_abc123",
"Approved": null,
"ServerLabel": "crm",
"Name": "create_contact",
"Arguments": "{\"email\":\"jane@northwind.example\"}",
"MCPToolID": 0,
"MessageID": 90415
}
- Decide con
POST /conversation/:id/approve, usando elIDnumérico de la entrada, noApprovalRequestID. - El servidor registra la decisión y ejecuta un nuevo turno de la IA que se la transmite al modelo. La continuación es un mensaje nuevo de la IA.
POST /conversation/:id/approve
/api/v1/conversation/:id/approve Aprueba o rechaza una llamada pendiente a una herramienta MCP.
-
idinteger en path obligatorio - ID numérico de la conversación.
-
approval_request_iduint obligatorio - El
IDde la entrada enmcp_approval_requests. -
is_approvedbool obligatorio truepara aprobar,falsepara rechazar.-
use_streambool opcional true: responde de inmediato y la continuación llega por el WebSocket o mediante sondeo.false: espera a que termine la continuación.
Respuesta. 200 con la cadena JSON "Successfully handled approval", no con un objeto. El mensaje de continuación no se devuelve: léelo con GET /conversation/:id o por el WebSocket.
Errores. 404 {"error":"Conversation not found"}, 404 {"error":"MCP Approval request not found"}, 400 {"error":"Approval request already processed"}, 400 {"error":"No messages in conversation"}, 500. La continuación usa el modelo fijo del siguiente mensaje de la conversación; en una conversación con enrutamiento automático, esto no es compatible.
Comparación de modelos
Una subconversación ejecuta el mismo mensaje con dos o más modelos en paralelo, con un «hilo» por modelo. Mientras está activa, los mensajes de seguimiento a la conversación principal van a todos los hilos. Al cerrarla, se elige un hilo ganador cuyo historial continúa en la conversación principal. Es la parte de la API de Comparar modelos.
POST /conversation/:id/sub-conversation
/api/v1/conversation/:id/sub-conversation Inicia una comparación y espera a que terminen todos los hilos.
-
idstring en path obligatorio - ID o slug de tu conversación (solo el propietario). Los valores literales
nulloundefinedcrean primero una conversación vacía nueva.
-
ai_model_idsuint[] obligatorio - Al menos 2 IDs de modelo.
-
messagestring opcional - El mensaje que se envía a todos los modelos.
-
prompt_instance_iduint opcional - En lugar de
message, ejecuta una instancia de prompt guardado en cada hilo. -
attachmentsarray opcional - Solo se usa con
prompt_instance_id. -
flash_modebool opcional - Solo se usa con
prompt_instance_id. -
reasoning_effortstring opcional - Solo se usa con
prompt_instance_id.
El estilo es el de la conversación; si no tiene, tu estilo preferido; y si tampoco hay, prompty.
Respuesta. 200 con el Message contenedor (type: "sub_conversation"). Su sub_conversation contiene parent_conversation_context_id, threads, selected_thread_id e is_active: true. Cada hilo tiene ai_model_id, ai_model, thread_conversation_context_id, thread_conversation_context (con messages), unsupported_files y credits_used.
Errores. 400 con menos de 2 modelos, 400 {"error":"AI model not found: <id>"}, 400 {"error":"An active sub-conversation already exists. Close it before creating a new one."}.
POST /conversation/:id/sub-conversation/stream
/api/v1/conversation/:id/sub-conversation/stream La variante con streaming: mismos parámetros de ruta y mismo cuerpo, pero responde en cuanto existen los mensajes del usuario. Después, las respuestas de los hilos se transmiten por el WebSocket de la conversación principal, y en la respuesta el messages de cada hilo contiene solo el mensaje del usuario.
POST /sub-conversation/:id/close
/api/v1/sub-conversation/:id/close Cierra una comparación activa en una conversación de la que eres propietario.
-
idinteger en path obligatorio - ID numérico de la subconversación (
sub_conversation_idosub_conversation.ID).
-
ai_model_iduint obligatorio - Pasa a ser el modelo del siguiente mensaje de la conversación principal. Debe ser mayor que 0.
-
ai_stylestring opcional - Pasa a ser el estilo de la conversación principal.
-
thread_iduint opcional - El hilo ganador.
0significa ninguno.
Respuesta. 204 No Content. Errores. 404 si no existe o no está activa.
POST /sub-conversation/:id/select-thread
/api/v1/sub-conversation/:id/select-thread Cambia el hilo cuyos mensajes cuentan como historial de la conversación. La subconversación debe estar cerrada; solo el propietario.
-
idinteger en path obligatorio - ID numérico de la subconversación.
-
thread_iduint obligatorio - Mayor que 0.
Respuesta. 204 No Content.
Compartir
Los cuatro endpoints de compartir usan el ID numérico de la conversación y solo puede llamarlos el propietario (en caso contrario, 404 {"error":"Conversation not found"}).
POST /conversation/:id/share
/api/v1/conversation/:id/share Comparte la conversación mediante un enlace. Genera un slug público de 32 caracteres si aún no existe y establece isPublic: true. Lee la conversación compartida con GET /conversation/{public_slug}.
-
idinteger en path obligatorio - ID numérico de la conversación.
-
share_typestring obligatorio workspace(miembros de tu espacio de trabajo),internal(cualquier usuario de StickyPrompts con sesión iniciada que tenga el enlace) opublic(cualquier persona con el enlace).
Respuesta. 200 {"message":"Conversation shared successfully","publicSlug":"<32 chars>"}. Errores. 400 {"error":"Invalid share type"}.
POST /conversation/:id/revoke-share
/api/v1/conversation/:id/revoke-share Establece isPublic: false. El slug se conserva. Sin cuerpo.
-
idinteger en path obligatorio - ID numérico de la conversación.
Respuesta. 200 {"message":"Conversation share successfully revoked"}.
POST /conversation/:id/regenrate-share-slug
/api/v1/conversation/:id/regenrate-share-slug Sustituye el slug público para que los enlaces antiguos dejen de funcionar. La ruta se escribe regenrate, exactamente como se muestra. Sin cuerpo.
-
idinteger en path obligatorio - ID numérico de la conversación.
Respuesta. 200 {"slug":"<new 32 chars>"}.
POST /conversation/:id/share-with-teams
/api/v1/conversation/:id/share-with-teams Comparte la conversación en modo de solo lectura con tus equipos. La lista representa el estado deseado completo para tus equipos: se deja de compartir con cualquier equipo al que pertenezcas que no figure en ella, salvo con los equipos que ya tienen chat_contribute (como el equipo para el que se creó una conversación de equipo). También garantiza que exista un slug público.
-
idinteger en path obligatorio - ID numérico de la conversación.
-
sharesarray obligatorio - Elementos
{ "team_id": uint, "access_type": "chat_view" | "none" }. Aquí solo se puede concederchat_view;chat_contributese rechaza con400.
Respuesta. 200 {"message":"Conversation shared successfully with teams","publicSlug":"<32 chars>"}. Errores. 403 {"error":"You are not a member of team <name>"}, 404 si el equipo no existe.
Mensajes
POST /message/:id/export
/api/v1/message/:id/export Exporta un mensaje a un archivo DOCX o PDF, ya sea como enlace de descarga o directamente a una integración de almacenamiento conectada, como Google Drive. Debes ser el propietario de la conversación o tener al menos chat_view sobre ella.
-
idinteger en path obligatorio - ID numérico del mensaje.
-
formatstring obligatorio docxopdf.-
targetstring opcional - Vacío o
local: genera un archivo descargable. Si no, el identificador de un proveedor de almacenamiento conectado, por ejemplogoogle_drive. -
folder_idstring opcional - Carpeta de destino en el proveedor. Obligatorio para destinos que no sean locales.
-
namestring opcional - Nombre del archivo para los destinos de proveedor (la extensión se añade sola). De forma predeterminada, el título de la conversación.
Respuesta. 200 con exactamente una de estas dos formas:
{ "path": "https://<storage host>/<bucket>/<userId>/<random>.pdf" }
{ "entry": { "id": "...", "name": "Q4 subject lines.docx", "kind": "file", "mime_type": "...", "web_url": "...", "parent_id": "...", "...": "..." } }
Errores. 400 {"error":"invalid format"}, 400 {"error":"invalid folder_id"}, 400 {"error":"unknown export target"}, 403 {"error":"you are not allowed to export this message"} o una carpeta de destino sin permiso de escritura, 404 si no se encuentra el mensaje o la integración no está conectada, 409 {"error":"reconnect_required"}, 501 si el proveedor no admite subidas, 500.
Contenido relacionado
- Prompts y ejecuciones - ejecuta prompts guardados; cada ejecución crea una conversación.
- Errores, paginación y cuotas - formatos de error, motivos de
429y headers de paginación. - Referencia de herramientas de MCP -
send_message,get_conversation,list_conversations,delete_conversation.