VitrinaAPI

Configurar el agente que conversa

Publicar el borrador, conectar herramientas y atender solicitudes.

GET /ai-agents lista los agentes que responden por el workspace cuando nadie del equipo escribe primero. Cada uno trae un system_prompt, un modelo y las herramientas que puede llamar. También trae los skills que sabe aplicar y la base de conocimiento que puede citar.

Leer pide ai_agents:read; escribir, ai_agents:write.

Borrador y versión en vivo

Cada agente tiene dos caras. El system_prompt, el modelo y las herramientas ya wireadas son lo que corre ahora mismo. Todo lo que empieza con draft_ es un cambio a medio hacer que nadie más ve todavía.

curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001 \
  -H "Authorization: Bearer $VITRINA_KEY"
{
  "data": {
    "id": "a3a3a3a3-0000-4000-8000-000000000001",
    "name": "Asistente de ventas",
    "status": "active",
    "is_default": true,
    "model": "deepseek/deepseek-v4.1-flash",
    "system_prompt": "Eres un asistente de ventas. Responde de forma breve y cercana.",
    "published_version_id": "a3a3a3a3-1000-4000-8000-000000000007",
    "draft_system_prompt": null,
    "draft_updated_at": null,
    "created_at": "2026-08-04T19:07:05.226Z",
    "updated_at": "2026-09-17T14:49:02.893Z"
  }
}

model casi nunca se manda. La plataforma elige y administra el modelo de cada agente, y la UI nunca lo pide. Mandar model es un escape hatch y no un catálogo abierto.

Editar el borrador

curl -X PUT https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/draft \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "system_prompt": "Eres un asistente de ventas. Ahora también ofreces financiamiento.",
    "knowledge_tags": ["horarios", "garantia", "financiamiento"]
  }'

Nada de esto llega al runtime todavía. PUT /ai-agents/{id}/system-prompt es un atajo sobre lo mismo: edita solo el prompt, staged igual. GET /ai-agents/{id}/draft lee el borrador pendiente y DELETE lo descarta sin tocar lo que está en vivo.

Publicar

curl -X POST https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/publish \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Publicar copia el borrador a lo que corre, guarda una versión (GET /ai-agents/{id}/versions) y dispara ai_agent.publish.

Hay un freno. Si el agente tiene una suite golden de Agent Evals habilitada y su último veredicto está blocked o stale, la llamada responde 409 en vez de publicar. Antes de automatizar un publish, consulta el freno:

curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/publish-gate \
  -H "Authorization: Bearer $VITRINA_KEY"
{
  "data": {
    "gate": "clear",
    "suite": {
      "id": "b6b6b6b6-0000-4000-8000-000000000001",
      "name": "Golden",
      "kind": "golden"
    },
    "last_run": {
      "pass_rate": 91.2,
      "hard_fails": 0
    }
  }
}

Con force: true el publish se salta el freno, y queda en el registro de auditoría con quién lo hizo.

POST /ai-agents/{id}/versions/{version}/restore carga una versión pasada al borrador, para revisarla antes de publicar. POST /ai-agents/{id}/versions/{version}/rollback hace las dos cosas de una vez: carga y publica, y deja esa versión en vivo de inmediato.

Skills

Un skill es un playbook reutilizable que se adjunta a uno o más agentes: «cómo ofrecer horarios», «cómo pedir el número de referencia antes de confirmar». Vive en una biblioteca del workspace y no dentro de un agente en particular.

curl -X PUT https://api.vitrinadev.com/api/v1/skills/a4a4a4a4-0000-4000-8000-000000000001 \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Cuando el cliente quiera agendar, ofrece SOLO horarios de la sucursal más cercana y confirma antes de reservar."
  }'

Editar un skill es solo contenido y aplica al instante. No hay borrador ni publish para un skill: el cambio llega a cada agente que lo tiene adjunto en su próximo turno.

POST /ai-agents/{id}/skills adjunta uno que ya existe y DELETE /ai-agents/{id}/skills/{skillId} lo desadjunta sin borrarlo. DELETE /skills/{id} sí lo borra, con un borrado suave. Sale de la biblioteca y de todo agente al instante.

Herramientas

GET /ai-agents/tools-catalog lista lo que este workspace puede wirear hoy, filtrado por rubro e integraciones conectadas. PUT /ai-agents/{id}/tools reemplaza el set completo con tool_names, y aplica en vivo, no al borrador: el próximo turno del agente ya ve el cambio.

Herramientas personalizadas

Cuando la API que el agente necesita llamar es la del propio workspace, no hace falta escribir código. El Tool Store enseña el llamado como una plantilla.

curl -X POST https://api.vitrinadev.com/api/v1/custom-tools \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "consultar_clima",
    "description": "Consulta el clima actual de una ciudad",
    "parameters": [
      { "name": "ciudad", "type": "string", "description": "Nombre de la ciudad", "required": true }
    ],
    "request_template": {
      "method": "GET",
      "url": "https://api.example.com/weather?city=${param.ciudad}"
    }
  }'

Los valores de los parámetros se interpolan en la URL, los headers o el body como ${param.NOMBRE}. Una credencial se referencia como ${secret.NOMBRE} y nunca se escribe en la plantilla. POST /custom-tools/{id}/test hace la llamada real, porque no hay modo sandbox, y guarda cada invocación redactada para auditoría.

Cuando la API de destino pide autenticación, la credencial vive aparte, en /tool-credentials:

curl -X POST https://api.vitrinadev.com/api/v1/tool-credentials \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "weather_api_key", "kind": "api_key", "value": "wapi_live_abc123wx91" }'
{
  "data": {
    "id": "a7a7a7a7-0000-4000-8000-000000000002",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "name": "weather_api_key",
    "kind": "api_key",
    "value_preview": "••••wx91",
    "metadata": {},
    "created_by": "11111111-0000-4000-8000-000000000001",
    "created_at": "2026-09-12T10:00:00.000Z",
    "updated_at": "2026-09-12T10:00:00.000Z",
    "last_used_at": "2026-09-21T18:04:11.000Z",
    "rotation_grace_until": null
  }
}

El valor en texto plano nunca vuelve a mostrarse. Cada lectura trae solo value_preview, unos caracteres enmascarados, igual que una API key. Rotar es un PATCH con un value nuevo. El valor viejo sigue funcionando 24 horas más, así una llamada en curso no se rompe a mitad de la rotación.

Base de conocimiento

Un agente cita lo que tiene adjunto y no toda la biblioteca del workspace:

curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/knowledge \
  -H "Authorization: Bearer $VITRINA_KEY"

POST /ai-agents/{id}/knowledge sube un archivo nuevo directo al agente, en multipart, o adjunta uno que ya existe en la biblioteca con { "kb_file_id": "…" }. DELETE /ai-agents/{id}/knowledge/{fileId} desadjunta, y el archivo sigue existiendo y sirviendo a cualquier otro agente. Cómo se sube, genera y reemplaza un archivo está en Base de conocimiento.

Canal de voz

curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/voice-channel \
  -H "Authorization: Bearer $VITRINA_KEY"

Trae el estado de la línea, el saludo, la voz elegida de un catálogo curado y el número de derivación a un humano. Del saludo solo se edita el segmento de marca. El aviso de que es IA y de que la llamada se graba lo compone el servidor, y no se puede quitar. voice_id es una clave de ese catálogo y no un id propio del workspace.

PUT guarda el cambio y lo empuja a la capa de voz. Si el empuje falla queda pendiente, y POST /ai-agents/{id}/voice-channel/propagate reintenta.

Solicitudes: cuando un cliente pide un cambio

Una Solicitud (agent_change_request) es un requerimiento que alguien planteó con sus propias palabras: «no uses guiones», «si algo no está disponible, dile que lo vamos a conseguir». Es distinta de un hallazgo que la plataforma detectó sola.

curl -X POST https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/change-requests \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "verbatim": "No uses guiones largos, suena robótico.", "reporter_kind": "client_via_member" }'

También se puede archivar como audio (multipart/form-data, campo file). Se transcribe, y la transcripción es el verbatim, así que nada queda guardado que no se pudiera convertir a texto.

El ciclo de vida:

EstadoQué significa
receivedSe registró lo que dijo el cliente
groundedSe confirmó en qué conversación pasó
reproducedUn escenario reprodujo el problema contra la versión reclamada
proposedSe propuso un arreglo
appliedEl arreglo se aplicó
verifiedSe confirmó que el arreglo funciona
ya_cumpleEl agente ya lo hacía bien y la queja era sobre una versión vieja
harnessEl arreglo es de la plataforma y no del prompt de este agente

POST .../change-requests/{crId}/ground busca en qué conversaciones pasó, sin tocar nada. POST .../ground/confirm es la respuesta humana a esa búsqueda. POST .../scenario autoría un escenario de prueba desde la solicitud y lo corre contra la versión reclamada. POST .../propose investiga y guarda una propuesta de arreglo, una vez que el escenario reprodujo el problema en rojo.

Los eventos

EventoCuándo
ai_agent.publishUn borrador se publicó como configuración en vivo
skill.created / .updated / .deletedCambió la biblioteca de skills
custom_tool.created / .updated / .deletedCambió el Tool Store

ai_agent.publish lleva ai_agent_id, name y updated_at, lo justo para saber qué agente cambió y cuándo. El contenido de la publicación se lee con GET /ai-agents/{id}/versions.

En esta página