Integrar con un asistente de IA
La instrucción para pegar en tu asistente de IA y las reglas para que integre con la API sin preguntar a nadie ni romper nada.
Actualizado el . 6 min de lectura
Incluido en todos los planes. Ver precios
Pega esto en tu asistente de IA (Claude, ChatGPT, Cursor, Copilot...) al empezar. La clave va en una variable de entorno de tu equipo o de tu servidor: tu asistente no la necesita en la conversación.
Vas a integrar mi aplicación con la API externa de UTILIA OS.
Sigue https://os.utilia.ai/docs/developers/getting-started/ai-assistants
y consulta la documentación completa en https://os.utilia.ai/llms-full.txt.
La dirección base es https://os.utilia.ai/api y la clave está en la variable
UTILIA_API_KEY: no la escribas nunca en el código, en el repositorio ni en
esta conversación. Antes de programar, llama a
GET /external/v1/diagnostics?format=markdown y sigue lo que diga.Esta página es para escribir código que llama a la API. Para que tu asistente trabaje con los datos de tu organización sin programar, usa MCP.
Las reglas
Cada operación nueva pasa por el mismo orden. Los tres primeros pasos no escriben nada: repítelos tantas veces como haga falta, dentro de sus cupos. El mismo ciclo, con código en curl, JavaScript y Python, está en Probar tu integración.
- Diagnostica antes de programar.
GET /external/v1/diagnosticsdice qué puede llamar la clave, qué le falta y quién lo arregla; con?format=markdown, en forma de instrucciones. Leeverdict(el estado en una línea), despuésnextSteps(haz los defixedBy: developer; los deorganization, pídeselos a un administrador con el texto tal cual),access(no programes contra una operación conallowed: falsesin resolver sureason) yfindings, cada uno con sudocsUrlen Hallazgos del diagnóstico. - Comprueba cada petición nueva con
POST /external/v1/diagnostics/check-requesty el cuerpo que vas a mandar. Dice si pasaría, con el mismoerrorCodeque la llamada real, y qué campos descartaría sin avisar (validation.ignoredFields): un201sin el dato guardado. Lo que tu clave puede llamar, con sus esquemas, está enGET /external/v1/diagnostics/openapi.json. - Ensaya sin efectos cuando la ruta lo permita:
POST /external/v1/invoices/validatepara facturas (sin emitir nada),POST /external/v1/diagnostics/runpara las lecturas y los avisos de prueba para tu servidor. Las escrituras sin ensayo (un ticket, un cliente, un lead) se prueban concheck-requesty después con una llamada real sobre datos de prueba. - Llama de verdad. Si la ruta mueve dinero o emite un documento, manda una clave de idempotencia (
idempotencyKey) que salga de tu pedido, nunca una nueva en cada intento, y al emitir facturas pon un tiempo de espera de al menos 30 segundos. Después de cada escritura, miraX-Utilia-Ignored-Fields(los SDK avisan solos cononIgnoredFieldsyon_ignored_fields). - Lee el error en este orden:
errorCode, lo único por lo que decide tu código;fixedBy(developerlo arreglas tú;organization, un administrador, y no se rodea desde el código;utilia, nosotros);docsUrl, su explicación en Errores y reintentos;requiredScopes, en un403 INSUFFICIENT_SCOPE;retryableyRetry-After, si repetir puede funcionar y cuándo; yrequestId, para pedir ayuda. Si los fallos se repiten,GET /external/v1/diagnostics/callslos agrupa con su arreglo.
Con una clave publicada en una web (con dominios autorizados o usada desde un navegador), el diagnóstico llega recortado, con credential.publishable: true, y las llamadas rechazadas, la prueba activa y los avisos de prueba responden 403 DIAGNOSTICS_NOT_AVAILABLE_FOR_PUBLISHABLE_KEY: se lanzan desde la pestaña Pruebas del panel (por qué).
Y nunca:
- Emitas facturas para probar. La numeración fiscal no tiene vuelta atrás: valida con
/invoices/validate. - Escribas la clave en el código, en el repositorio, en la conversación ni en la dirección. Va en
UTILIA_API_KEYy en la cabeceraX-Api-Key. - Uses una clave de API de la organización en el navegador, ni la de la aplicación en una web sin dominios autorizados: cualquiera podría copiarla.
- Reintentes una escritura con otra clave de idempotencia, ni repitas una sin clave sin comprobar antes si llegó a hacerse.
- Rodees desde el código lo que arregla la organización: cambiar de ruta para saltarte un permiso o un plan no funciona y deja rastro.
- Ignores
X-Utilia-Ignored-Fieldsni loswarningsde un ensayo. - Insistas ante un
429sin esperar lo que digaRetry-After. - Te fíes de un aviso sin verificar su firma, ni guardes uno con
livemode: falseen tus datos de producción. - Llames con la clave de la aplicación a rutas fuera de
/api/external/v1: no son públicas y no responderán.
Qué credencial usar
La API externa (/api/external/v1) solo acepta la clave de una aplicación externa. La clave de API de la organización abre otra puerta, y cruzarlas da 401 API_KEY_WRONG_KIND.
Dos claves que se confunden
X-Api-Key: utl_...Recomendado
Clave de aplicación
Authorization: Bearer utk_...
Clave de la organización
/api/...), con los permisos de una persona. Se crea en Ajustes › Claves de API y nunca vale desde un navegador.La clave de aplicación va siempre en la cabecera X-Api-Key: en Authorization da 401 API_KEY_WRONG_HEADER, y sola en la dirección (apiKey, api_key, x-api-key...), 401 API_KEY_IN_URL_NOT_ALLOWED. Si va en la dirección y también en la cabecera, de momento entra, pero el diagnóstico avisa con KEY_IN_URL: quítala de la dirección y pide que se renueve. Las demás credenciales están comparadas en Autenticación con clave de acceso y en Claves de API de la organización.
Las rutas y los SDK
Todas con la clave en X-Api-Key y sin permisos de la API. En los SDK, desde la 4.6.0; con una versión anterior, llama a las rutas directamente (Versiones y compatibilidad).
| Ruta | JavaScript | Python |
|---|---|---|
GET /external/v1/me | sdk.diagnostics.me() | sdk.diagnostics.me() |
GET /external/v1/diagnostics | sdk.diagnostics.get() | sdk.diagnostics.get() |
GET /external/v1/diagnostics?format=markdown | sdk.diagnostics.getMarkdown() | sdk.diagnostics.get_markdown() |
GET /external/v1/diagnostics/calls | sdk.diagnostics.calls() | sdk.diagnostics.calls() |
POST /external/v1/diagnostics/check-request | sdk.diagnostics.checkRequest() | sdk.diagnostics.check_request() |
POST /external/v1/diagnostics/run | sdk.diagnostics.run() | sdk.diagnostics.run() |
POST /external/v1/diagnostics/webhook-sample | sdk.diagnostics.sendWebhookSample() | sdk.diagnostics.send_webhook_sample() |
POST /external/v1/diagnostics/webhook-receiver-check | sdk.diagnostics.checkWebhookReceiver() | sdk.diagnostics.check_webhook_receiver() |
GET /external/v1/diagnostics/openapi.json | sdk.diagnostics.openApi() | sdk.diagnostics.open_api() |
Cada ruta, con sus campos y sus cupos, está en Rutas del diagnóstico.
La orden doctor
Hace el diagnóstico completo desde la consola y lo enseña ordenado, con quién arregla cada cosa y sus enlaces. Lee la clave de UTILIA_API_KEY y nunca la muestra. Llega con los SDK 4.6.0 (si ya se puede instalar).
export UTILIA_API_KEY=...
export UTILIA_BASE_URL=https://os.utilia.ai/api
npx @utilia-os/sdk-js doctor # diagnóstico
npx @utilia-os/sdk-js doctor --run # y prueba activa de solo lectura
npx @utilia-os/sdk-js doctor --check "POST /external/v1/invoices" --body factura.json
npx @utilia-os/sdk-js doctor --json --strict # para tu asistente o tu CISale con un código que tu asistente o tu integración continua pueden leer:
-
0: no hay nada que bloquee. -
1: hay hallazgos que bloquean (con--strict, también los avisos), una prueba activa que falla o una petición de--checkque no pasaría. También si el servidor responde que la aplicación está desactivada, sin persona responsable activa o con la organización bloqueada. -
2: no se pudo comprobar: sin conexión, una clave que no vale, una direcciónhttp://que no admite o la orden mal escrita. -
La clave solo viaja cifrada: con una dirección
http://, la orden se niega a mandarla y sale con2, salvo que apunte a este mismo equipo (localhost,127.0.0.1o::1).--allow-insecure-httpla deja pasar con un aviso: solo para un laboratorio aislado, nunca contra un servidor de verdad. -
Con una clave publicada en una web,
--runno lanza la prueba activa: lo explica, no lo cuenta como fallo y, con--json, lo anota ennotices. -
Con
--jsonsaca el diagnóstico tal cual, conrunycheckRequestsi los pides: es la forma más cómoda de dárselo a un asistente.
La documentación en texto
https://os.utilia.ai/llms.txt: el índice de la documentación pública, con un enlace por artículo y al texto completo. Es el que citan las instrucciones del diagnóstico.https://os.utilia.ai/llms-full.txt: el texto completo de la documentación para desarrolladores, en Markdown, en un solo fichero.- El contrato de tu clave:
GET /external/v1/diagnostics/openapi.json, con solo lo que tu clave puede llamar. - Copiar › Copiar para tu IA, en la cabecera de cada artículo, copia ese artículo en Markdown. Está en el ordenador; en el teléfono, la cabecera ofrece Compartir.