API Core Documentación

v1 · REST
Home

Visión general

Autenticación, envío de jobs, resultados, catálogo de engines, webhooks y canales de notificación.

Esta referencia cubre 12 endpoints. Cada endpoint trae ruta, permiso, parámetros, respuesta y los errores posibles.

Crear cuenta

Compartir
POST/api/v1/register
Auth
anónima, exige X-PLATFORM-KEY
Base
https://intelligence.echosistema.live

Propósito

Alta self-service de evaluación: crea la cuenta de quien la solicita y el tenant de evaluación detrás de ella, y devuelve una clave de API ya funcionando. Es la única escritura anónima de esta superficie - existe para crear el propio tenant que todas las demás rutas autentican.

X-PLATFORM-KEY

Obligatorio. Debe coincidir con la clave pública del despliegue; sin él, o con un valor distinto, la respuesta es 401 y no se crea nada. Es un filtro que mantiene a los escáneres y a las altas automatizadas fuera de una ruta que por lo demás está abierta, no autenticación: el valor viaja dentro del bundle del front-end, así que trátalo como público.

Las defensas reales son otras y no han cambiado: la ruta solo existe donde el alta self-service está configurada (404 en caso contrario), los intentos se limitan por dirección de origen por hora (los rechazados incluidos, y una clave de plataforma equivocada cuenta), y el rol de base de datos detrás de ella tiene INSERT sin SELECT. Un despliegue sin clave pública configurada rechaza toda alta con 503 en lugar de aceptarlas sin filtro.

Campos

Solo name, email, password y accepted_terms son obligatorios. company_name es el discriminador: presente, la cuenta es de una empresa; ausente, la persona es la cuenta.

CampoTipoObligatorioSignificado
namestringNombre de quien crea la cuenta
emailstringCorreo de la cuenta, también el identificador de acceso
passwordstringContraseña inicial; la política es la del proveedor de identidad
accepted_termsbooleanDebe ser true; false responde 400
company_namestringnoEl discriminador de cuenta empresarial
phonestringnoTeléfono de contacto
countrystringnoPaís
websitestringnoSitio web
tax_idstringnoIdentificación fiscal
users_countenteronoCantidad estimada de usuarios
purposestringnoUso previsto de la plataforma
sourcestringnoOrigen del alta, para atribución

Respuesta

201 con {"customer_uuid": "...", "api_key": "...", "trial_ends_at": "...", "plan": {...}}.

La api_key vuelve una sola vez. Solo se almacena un digest con clave, y nada la recupera después: guárdala en el momento en que aparece. Para reemplazarla, POST /api/v1/tenant/api-key/rotate.

plan trae el código del plan de evaluación y sus límites (max_jobs_per_day, max_requests_per_min, max_upload_mb, retention_days), omitiendo los que sean ilimitados.

Errores

EstadoCuándo
400Un campo falló la validación, no se aceptaron los términos, o la contraseña fue rechazada por la política
401X-PLATFORM-KEY ausente o distinto
404El despliegue no configuró el alta self-service
409Este correo ya tiene cuenta
429Ventana horaria de intentos agotada
503El despliegue no configuró la clave pública
Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/register
AUTENTICACIÓN
X-PLATFORM-KEY

Ruta anónima, filtrada por la clave pública de la plataforma. El campo ya viene con la clave de este portal.

REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/register" \
  -H "X-PLATFORM-KEY: eb7f5270-9b15-3d54-9bad-9f1b15489295" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Agrias Oaks", "email": "agrias@empresa.exemplo", "password": "trocar-esta-senha-1", "accepted_terms": true, "company_name": "Empresa Exemplo", "country": "BR", "website": "https://empresa.exemplo", "tax_id": "00.000.000/0001-00", "users_count": 12, "purpose": "Avaliar os engines de previsão de demanda" }'

Datos de la empresa

Compartir
Ruta
GET /api/v1/company
Auth
Authorization: Bearer con el rol de administrador
Base
https://intelligence.echosistema.live

Propósito

El registro comercial de la propia empresa, tal como fue dado de alta: quién la registró, para qué, y cómo contactarlo.

Es distinto de GET /api/v1/me, que trae los derechos de la empresa - plan, cuotas, límites - y distinto de Equipo de la empresa, que trae las personas.

Campos

CampoTipoSignificado
customer_uuidstringLa empresa a la que pertenece este registro
company_namestringRazón social. Ausente cuando la cuenta es la propia persona
contact_namestringNombre de quien registró
emailstringEl correo usado en el alta
phone, country, website, tax_idstringComo fueron informados, cuando lo fueron
users_countnumberCantidad de personas declarada
purposestringFinalidad declarada
sourcestringDe dónde vino el alta
accepted_terms_atstringCuándo se aceptaron los términos
registered_atstringCuándo se escribió el registro
registered_byobjetouser_id siempre; email y name cuando el proveedor aún tiene a la persona

Lo que esta ruta nunca devuelve

La dirección de red y el navegador del alta. Existen para responder si un alta fue un script, y el rol de base detrás de esta ruta no tiene permiso de lectura sobre esas columnas - una consulta que las pidiera sería rechazada por Postgres antes de que existiera respuesta. No es una omisión de quien escribió el handler; es un permiso que no existe.

Errores

StatusCuándo
401Sin token, o con una API key
403Quien llama no administra esta empresa, o está inactiva
404Esta empresa no tiene registro comercial
500Fallo de dependencia

404 es una respuesta legítima, no un error de implementación. Una empresa aprovisionada fuera del alta self-service nunca completó ese registro. Su perfil es el bloque organization de GET /api/v1/me.

Editar empresa

Compartir
PATCH/api/v1/company
Auth
Authorization: Bearer con el rol de administrador de la empresa
Base
https://intelligence.echosistema.live

Propósito

Edita el perfil de la propia empresa de quien llama. La empresa viene del token: no existe parámetro de tenant y, por lo tanto, no existe camino para editar otra.

Una clave de API se rechaza con 401 - nombra a una empresa, no a una persona, y no prueba quién está autorizado a editarla. Sin el rol company-<tenant>-administrator en el token, 403.

Campos editables

Envía solo lo que cambia. Una cadena vacía limpia un campo opcional; name no puede vaciarse.

CampoTipoNota
namestringNo acepta cadena vacía
countrystringLa cadena vacía limpia
websitestringLa cadena vacía limpia
tax_idstringLa cadena vacía limpia
users_countentero
purposestringLa cadena vacía limpia

Contactos y personas no son editables aquí: el dato de persona pertenece al proveedor de identidad.

Renombrar

Cambiar el nombre también renombra la organización en el proveedor de identidad, para que ambos lados coincidan. Un nombre que otra organización ya ocupa responde 409 y no se altera nada.

Respuesta

200 con el mismo envoltorio de GET /api/v1/me, releído después de la escritura.

Errores

EstadoCuándo
400Un campo falló la validación, o name vino vacío
401Sin token, token inválido, o se presentó una clave de API
403El token no lleva el rol de administrador de esta empresa
409Otra organización ya ocupa ese nombre
Probar solicitudOPENAPI
PATCH
https://intelligence.echosistema.live/api/v1/company
AUTENTICACIÓN
AuthorizationBearer

Esta ruta acepta solo el token: una clave de API nombra a una empresa, no a una persona, y se rechaza con 401 aunque sea válida.

REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X PATCH "https://intelligence.echosistema.live/api/v1/company" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Empresa Exemplo S.A.", "website": "https://empresa.exemplo" }'

Equipo de la empresa

Compartir
Ruta
GET /api/v1/company/users
Auth
Authorization: Bearer con el rol de administrador
Base
https://intelligence.echosistema.live

Propósito

Quién forma parte de la propia empresa: todos los que son miembros de su Organization en el proveedor de identidad, con los roles de empresa que tiene cada uno.

La empresa viene del token y no puede nombrarse en la petición - esta ruta solo sabe responder por la empresa de quien llama.

Campos de cada persona

CampoTipoSignificado
idstringEl id de la persona en el proveedor de identidad
emailstringEl correo de acceso, cuando el proveedor tiene uno
namestringEl nombre, cuando el proveedor tiene uno
enabledbooleanSi el proveedor la dejaría entrar
email_verifiedbooleanSi el proveedor considera el correo comprobado
rolesarrayRoles de empresa: administrator, supervisor, coordinator, support, developer

email y name se omiten cuando el proveedor no los tiene - nunca vuelven nulos. Una persona sin nombre en el proveedor aparece por su correo.

Quién aparece

Quien es miembro de la Organization. Alguien con un rol company-<empresa>-* que fue retirado de la Organization no aparece: eso es residuo de un rol concedido con una pertenencia deshecha, y listarlo respondería "¿quién es de esta empresa?" con quien no lo es.

Un miembro sin ningún rol vuelve con roles: []. Y solo administrator tiene autoridad en esta API - los otros cuatro son etiquetas que lee el producto, y ninguna ruta los verifica.

Límite

El listado se detiene en 200 personas. No hay paginación: una empresa es un equipo, no un directorio.

Errores

StatusCuándo
401Sin token, o con una API key
403Quien llama no administra esta empresa, o está inactiva
503Proveedor inaccesible, o entorno sin credencial de administración
404El proveedor de identidad no tiene organización para esta empresa

Los datos se leen del proveedor en cada llamada - este servicio no guarda personas. Por eso un proveedor caído responde 503, y no una lista vacía que se leería como "la empresa no tiene a nadie".

Añadir persona

Compartir
POST/api/v1/company/users
Auth
Authorization: Bearer con el rol de administrador
Base
https://intelligence.echosistema.live

Propósito

Añade una persona a tu propia empresa: la crea en el proveedor de identidad, la hace miembro de la Organization de la empresa y le concede un rol.

Campos

CampoTipoSignificado
namestringSu nombre; se acepta un nombre único
emailstringSerá su usuario en el proveedor, y es la clave de unicidad
passwordstringValor de primer acceso - ver abajo
rolestringmaster, administrator, supervisor, coordinator, support o developer

El rol se convierte en company-<tenant>-<rol> en el proveedor, la forma que ya usa el resto de la plataforma.

Solo master y administrator tienen autoridad

Son ellos los que permiten añadir, quitar y re-rolar personas, editar la empresa y rotar la clave; master puede todo lo que puede administrator. Los otros cuatro son etiquetas que lee el producto: ninguna ruta los comprueba hoy.

El conjunto es cerrado del lado de la API y GET /api/v1/company/roles lo devuelve entero, con la antigüedad (rank) y quién tiene autoridad (administers). Arma el selector a partir de ahí: una lista repetida en el cliente diverge el día en que aparezca un séptimo rol.

La contraseña es de traspaso

La eligió otra persona y viajó por un tercero hasta llegar. Por eso el usuario nace con el cambio de contraseña pendiente en el proveedor: ese valor funciona una sola vez, y la persona define la suya en el primer inicio de sesión. También por eso esta ruta no depende de tener correo configurado.

Respuesta

201 con id, email y el rol concedido por extenso.

Errores

StatusCuándo
400Un campo vacío, demasiado largo, o una contraseña que el proveedor rechazó
401Sin token, o se presentó una API key
403Quien llama no administra esta empresa
409Ese correo ya tiene cuenta

Un fallo a medio camino elimina lo ya creado, así que reintentar con el mismo correo es la recuperación soportada.

Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/company/users
AUTENTICACIÓN
AuthorizationBearer

Esta ruta acepta solo el token: una clave de API nombra a una empresa, no a una persona, y se rechaza con 401 aunque sea válida.

REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/company/users" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Ramza Beoulve", "email": "ramza@empresa.exemplo", "password": "trocar-esta-senha-3", "role": "supervisor" }'

Rotar clave de API

Compartir
POST/api/v1/tenant/api-key/rotate
Auth
Authorization: Bearer con el rol de administrador de la empresa
Base
https://intelligence.echosistema.live

Propósito

Emite una clave de API nueva para la empresa autenticada y la devuelve una sola vez. La clave anterior dejó de funcionar antes de que esta respuesta se escribiera.

La única ruta cuya credencial no es intercambiable

Cualquier otra ruta autenticada acepta X-TENANT-KEY o Authorization: Bearer. Esta acepta solo el token, y rechaza la clave de forma explícita en lugar de simplemente ignorarla: la clave es lo que se está reemplazando, así que honrarla dejaría que quien tiene una clave filtrada la rotara y dejara fuera al dueño real. Reemplazar un secreto se prueba por identidad, nunca por el secreto.

El rol exigido es company-<customer_uuid>-administrator para la misma empresa que el token resuelve: un administrador válido de otra empresa recibe 403.

Respuesta

200 con {"customer_uuid": "...", "api_key": "...", "rotated_at": "..."}.

La api_key aparece aquí y en ningún otro lugar - solo se almacena un digest con clave.

Errores

EstadoCuándo
401Sin token, token inválido, o se presentó una clave de API
403El token no lleva el rol de administrador de esta empresa
404El despliegue no configuró el alta self-service
429Ventana de peticiones por minuto agotada
500Fallo de dependencia; el motivo se registra, nunca se devuelve
Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/tenant/api-key/rotate
AUTENTICACIÓN
AuthorizationBearer

Esta ruta acepta solo el token: una clave de API nombra a una empresa, no a una persona, y se rechaza con 401 aunque sea válida.

Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/tenant/api-key/rotate" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Iniciar sesión

Compartir
POST/api/v1/auth/login
Auth
anónima - es la ruta que produce la credencial
Base
https://intelligence.echosistema.live

Propósito

Cambia e-mail y contraseña por la sesión del proveedor de identidad. El token devuelto es el del propio proveedor, sin modificar: es el mismo que verifican todas las demás rutas.

Dos modos, elegidos por la cabecera X-PLATFORM-KEY

ModoCuándoQué vuelve
tokenEnvías una platform key válidaaccess_token y refresh_token en el cuerpo
cookieNo envías platform keyCookies HttpOnly; el cuerpo no trae token

El modo token es para clientes que pueden guardar una credencial: app nativa, integración server-side, script. El modo cookie (BFF) es para el navegador, que no puede: lo que el script lee, un XSS también.

Una key incorrecta no es ninguno de los dos - responde 401. Caer al modo cookie haría inútil la cabecera, ya que quien quisiera el modo seguro solo tendría que omitirla. Lee el campo session para saber qué modo te tocó.

Campos

CampoTipoSignificado
emailstringEl e-mail de la persona, que es su usuario en el proveedor
passwordstringSu contraseña

Respuesta

200 con session, expires_in, user, companies y, cuando hay una empresa que describir, tenant. En modo token, además access_token, refresh_token y token_type.

El bloque user trae nombre, e-mail y el avatar definido con PATCH /api/v1/me, leídos de los claims del propio token. El bloque tenant es el mismo envelope de GET /api/v1/me - y los límites salen de la base de datos, nunca de un claim.

companies siempre viene; tenant puede faltar

companies lista todas las empresas de la persona que este entorno atiende, con una entrada en el caso común. tenant falta cuando pertenece a más de una: no hay empresa que describir antes de que una sea elegida, y elegir aquí sería elegir a quién servirle los datos.

La regla es la misma de todas las otras rutas: el bloque está presente cuando una solicitud sin la cabecera X-COMPANY resolvería una empresa, y ausente cuando preguntaría cuál. Quien pertenece a una sola no ve ninguna diferencia - pero el código ya no puede asumir que tenant existe.

El modo cookie asume same-site

Las cookies llevan Path=/ y ningún Domain: el front-end y la API deben ser un mismo sitio, con un proxy inverso delante de ambos. Un front-end en otro dominio nunca las envía y debe usar el modo token. SameSite=Lax es la defensa CSRF - un POST cross-site no lleva cookie alguna.

Errores

StatusCuándo
400Un campo vacío o demasiado largo
401Credenciales rechazadas, o X-PLATFORM-KEY presente e incorrecta
403La empresa está inactiva o suspendida
429Ventana horaria de intentos agotada para esta dirección
503Proveedor de identidad inalcanzable, o sin client de login configurado

E-mail incorrecto, contraseña incorrecta y cuenta deshabilitada responden el mismo 401: distinguirlos convertiría esta ruta en una forma de averiguar qué e-mails tienen cuenta. La contraseña nunca la guarda este servicio.

Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/auth/login
AUTENTICACIÓN
X-PLATFORM-KEY

Ruta anónima, filtrada por la clave pública de la plataforma. El campo ya viene con la clave de este portal.

REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/auth/login" \
  -H "X-PLATFORM-KEY: eb7f5270-9b15-3d54-9bad-9f1b15489295" \
  -H "Content-Type: application/json" \
  -d '{ "email": "agrias@empresa.exemplo", "password": "trocar-esta-senha-1" }'

Renovar sesión

Compartir
Ruta
POST /api/v1/auth/refresh
Auth
el propio refresh token (cuerpo o cookie)
Base
https://intelligence.echosistema.live

Propósito

Renueva la sesión sin volver a pedir la contraseña, respondiendo en el mismo modo en que fue llamada: con refresh_token en el cuerpo, los nuevos tokens vuelven en el cuerpo; con el cuerpo vacío, se reemplazan las cookies de sesión.

No hace falta platform key - el refresh token es la credencial, y un navegador en modo cookie no tiene cabecera que enviar.

Campos

CampoTipoSignificado
refresh_tokenstringSolo en modo token; omítelo en modo cookie

Errores

StatusCuándo
401Sin refresh token, o el proveedor lo rechazó - inicia sesión de nuevo
403La empresa fue suspendida desde el inicio de sesión
503Proveedor inalcanzable, o sin client de login configurado

La empresa se vuelve a comprobar en cada renovación, así que una suspensión termina la sesión en la siguiente en lugar de aparecer después como un fallo inexplicable.

Cerrar sesión

Compartir
Ruta
POST /api/v1/auth/logout
Auth
anónima
Base
https://intelligence.echosistema.live

Propósito

Termina la sesión. Las cookies se limpian en esta respuesta siempre; al proveedor se le pide terminar la suya en modo best effort, de modo que un proveedor inalcanzable nunca bloquea el cierre.

Campos

CampoTipoSignificado
refresh_tokenstringSolo en modo token, para terminar también la sesión del proveedor

En modo token, descarta el access token por tu lado - eso no puede hacerlo el servidor por ti.

Respuesta

204 No Content, incluso cuando no había sesión: cerrar sesión de nada no es un error, y rechazarlo dejaría a alguien con el token ya expirado sin poder limpiar su propio navegador.

Validar credencial

Compartir
GET/api/v1/auth
Auth
X-TENANT-KEY o Authorization: Bearer
Base
https://intelligence.echosistema.live

Propósito

Valida la credencial presentada y devuelve la identidad y los entitlements del llamante. No se emite ningún token - la emisión de tokens corresponde al proveedor de identidad. Los secretos (ej.: webhook_secret) nunca se incluyen en la respuesta.

Cuando la credencial es un token - de la cabecera o de la cookie de sesión - la respuesta trae además el bloque user, con la persona detrás de él. Ver Identidad actual, donde el bloque está descrito por completo.

Los tres métodos de autenticación

Las credenciales se prueban en un orden fijo, sin fallthrough: una credencial presentada que falla produce 401, nunca un reintento con el método siguiente.

  • API key (X-TENANT-KEY) - el servidor almacena solo hex(HMAC-SHA256(key, pepper)) y la resuelve con una única consulta indexada O(1) más una comparación en tiempo constante. Las claves nunca se almacenan ni se registran en claro.
  • JWT (Authorization: Bearer) - la misma ruta de verificación sirve para tokens de usuario y tokens de máquina (client_credentials). El token debe ser RS256 (fijado: alg:none y HS256 se rechazan), firmado por una clave del JWKS del realm, con iss, exp y, cuando está configurado, aud válidos. Solo se lee la claim organization - la empresa *es* el id de la organización en el proveedor. Los entitlements vienen SIEMPRE de la base de datos en cada request; las claims que falsifican entitlements se ignoran.
  • Empresa activa (X-COMPANY) - no es un cuarto método, sino lo que dice para qué empresa es la petición cuando la persona pertenece a más de una. Con una empresa se resuelve sola y la cabecera sobra; con varias y sin la cabecera, la respuesta es 400 pidiendo que nombre una. La cabecera estrecha, nunca concede: una empresa fuera del token es 403, como si hubiera sido inventada. Ver Empresas de la persona.
  • Token de operador (X-Admin-Token) - concede únicamente la vista de operador de GET /api/v1/platform/health, sin acceso a datos de tenant. Queda totalmente deshabilitado cuando la variable correspondiente no está definida en el deploy.

Envelope uniforme de fallo

StatusCuerpo
401{"error": "missing credentials"} o {"error": "invalid credentials"}
403{"error": "tenant inactive or suspended"}
429{"error": "rate limit exceeded"}

Respuesta

200 con {"authenticated": true, "tenant_id": "...", "subscription_code": "...", "allowed_engines": null, ...}. allowed_engines: null significa todas las engines del catálogo.

Entitlements

Leídos en cada request desde la base de datos (JOIN de tenants con suscripciones), con caché en memoria breve (15s por defecto). Nunca desde una claim del token.

CampoOrigenSignificado
allowed_enginessuscripciónAllowlist de engines; NULL = todas las catalogadas
max_jobs_per_daysuscripciónCuota diaria de envíos; NULL = ilimitado
max_requests_per_minsuscripciónCuota de requests por minuto; NULL = ilimitado
max_upload_mbsuscripciónTecho de tamaño de subida por envío
retention_dayssuscripciónVentana de retención de resultados no efímeros
webhook_url / webhook_secret / webhook_eventstenantConfiguración del webhook de finalización
default_result_modetenantConfiguración legada de otro flujo de integración; los envíos por la API corren siempre en modo queue (este servicio es su almacenamiento)
ip_allowlisttenantPresente en el esquema pero NO aplicado en esta versión. No confíes en él.
Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/auth
AUTENTICACIÓN
X-TENANT-KEY
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/auth" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Empresas de la persona

Compartir
Ruta
GET /api/v1/companies
Auth
Authorization: Bearer
Base
https://intelligence.echosistema.live

Propósito

La única ruta que responde antes de que haya empresa elegida. Todo lo demás en esta API sirve los datos de una empresa y por eso necesita saber cuál; esta dice entre cuáles elegir.

Una persona puede ser miembro de varias empresas. El token las nombra todas, y cada solicitud sirve una: cuál de ellas va en la cabecera X-COMPANY, cuyo valor es el customer_uuid de una de estas entradas.

La cabecera X-COMPANY

SituaciónRespuesta
Una empresa, sin la cabeceraSirve esa - nada cambia para quien ya integra
Varias empresas, sin la cabecera400 pidiendo que nombres una
Cabecera con una empresa que el token nombraSirve esa
Cabecera con cualquier otra403

La cabecera estrecha, nunca concede. Elige entre lo que la credencial ya probó; una empresa fuera del token se rechaza como si hubiera sido inventada.

Campos de cada entrada

CampoTipoSignificado
customer_uuidstringEl valor a enviar en X-COMPANY en las llamadas siguientes
namestringNombre de la empresa, cuando un alta dejó uno
activebooleanEmpresa y suscripción vivas. Una suspendida se lista, no se esconde
subscription_codestringCódigo del plan
is_administratorbooleanSi esta persona administra esta empresa

Respuesta

200 con {"companies": [...], "count": n}.

Lista lo que este entorno puede servir, no todo lo que el proveedor de identidad conoce: alguien puede pertenecer a una organización para la que no hay empresa aquí, y ofrecerla sería ofrecer una elección que falla en la llamada siguiente.

is_administrator viene de los roles del propio token, los mismos que las rutas de administración verifican. Se informa temprano para que un cliente dibuje la pantalla correcta, en vez de descubrir la respuesta en un 403.

Errores

StatusCuándo
401Sin credencial, o con una que no es un token de persona
500Falló la lectura de los derechos de las empresas

Identidad actual

Compartir
GET/api/v1/me
Auth
X-TENANT-KEY, Authorization: Bearer o la cookie de sesión

Propósito

La misma identidad de GET /api/v1/auth. Solo devuelve el contexto del propio llamante - no existe ruta cross-tenant - y rechaza a un llamante anónimo con 401, como cualquier ruta autenticada.

El bloque user

Ambas rutas traen un bloque user cuando la credencial es un token, ya sea de la cabecera Authorization o de la cookie de sesión:

{
  "authenticated": true,
  "tenant_id": "...",
  "subscription_code": "trial",
  "user": {
    "id": "8f1c...",
    "name": "Agrias Oaks",
    "email": "agrias@empresa.exemplo",
    "avatar_url": "https://storage.echosistema.live/live/avatar/exemplo.png"
  }
}
CampoCuándo
idSiempre presente en el bloque - el id de la persona en el proveedor de identidad
name, emailCuando el proveedor emite el claim
avatar_urlCuando se definió un avatar con PATCH /api/v1/me

Así retoma la sesión un navegador. Quien entró en modo cookie no guarda nada que sus propios scripts puedan leer; llamar a esta ruta tras un reload es como averigua si la sesión sobrevivió y de quién es.

Con X-TENANT-KEY el bloque está ausente, y esa ausencia es información y no un hueco: una key nombra una empresa y ninguna persona. Todo en él se relaya de los claims del propio token - este servicio no guarda nada sobre la persona más allá de la organización a la que pertenece.

Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/me
AUTENTICACIÓN
X-TENANT-KEY
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/me" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Actualizar perfil

Compartir
PATCH/api/v1/me
Auth
solo Authorization: Bearer
Base
https://intelligence.echosistema.live

Propósito

Edita el perfil de la persona autenticada: avatar, idioma, moneda y género. Solo acepta token - una clave de API nombra a una empresa, no a una persona, y se rechaza con 401.

Cada campo se convierte en atributo de la persona en el proveedor de identidad, de modo que el siguiente token de acceso ya lo lleva como claim (picture, language, currency, gender). Este servicio no almacena nada sobre la persona.

Campos

CampoTipoSignificado
avatar_urlstringURL absoluta http(s) del avatar
languagestringEtiqueta de idioma de hasta 5 caracteres, normalizada a pt-BR
currencystringHasta 3 letras, guardada en mayúsculas (pyg pasa a PYG)
genderstringm, f u o, en cualquier caja

Parcial y campo a campo

Un campo ausente o null no toca lo que había, "" elimina el atributo, y un valor lo reemplaza. uuid no es editable: enviarlo se rechaza con 400, no se ignora en silencio.

Solo se comprueba la forma, nunca el significado: la URL del avatar debe ser absoluta http(s) y nunca es descargada por este servicio; idioma y moneda se normalizan, no se consultan en ninguna tabla.

El claim solo cambia con un token nuevo

El token que ya tienes sigue llevando los valores anteriores. Después de editar, renueva la sesión (POST /api/v1/auth/refresh) para leerlos de vuelta - GET /api/v1/me describe la empresa y la persona, no estas preferencias.

Respuesta

204 No Content.

Errores

EstadoCuándo
400Un campo no pasó la comprobación de forma, o llegó un campo desconocido
401Sin token, token inválido, o se presentó una clave de API
404El proveedor de identidad ya no tiene a esta persona
503El proveedor no declaró uno de los atributos; es un cambio de configuración suyo, no un error de cliente
Probar solicitudOPENAPI
PATCH
https://intelligence.echosistema.live/api/v1/me
AUTENTICACIÓN
AuthorizationBearer

Esta ruta acepta solo el token: una clave de API nombra a una empresa, no a una persona, y se rechaza con 401 aunque sea válida.

REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X PATCH "https://intelligence.echosistema.live/api/v1/me" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "avatar_url": "https://storage.echosistema.live/live/avatar/exemplo.png" }'

Cambiar contraseña

Compartir
POST/api/v1/me/password
Auth
solo Authorization: Bearer
Base
https://intelligence.echosistema.live

Propósito

Reemplaza la contraseña de la persona autenticada en el proveedor de identidad. Solo acepta token, por la misma razón que PATCH /api/v1/me.

Campos

CampoTipoSignificado
new_passwordstringLa contraseña nueva

No se pide la contraseña actual

Un token válido es lo que autoriza el cambio, así que el tiempo de vida de token definido en el proveedor es lo que limita la exposición de un token robado. La política de contraseñas es la del proveedor - un rechazo vuelve como 400. La contraseña nunca llega a la base de datos de este servicio.

Respuesta

204 No Content.

Errores

EstadoCuándo
400El proveedor rechazó la contraseña por su política
401Sin token, token inválido, o se presentó una clave de API
Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/me/password
AUTENTICACIÓN
AuthorizationBearer

Esta ruta acepta solo el token: una clave de API nombra a una empresa, no a una persona, y se rechaza con 401 aunque sea válida.

REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/me/password" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "new_password": "trocar-esta-senha-2" }'

Enviar job

Compartir
POST/api/v1/{engine}/process
Auth
X-TENANT-KEY o Authorization: Bearer
Formas
JSON inline o multipart/form-data con archivo

Propósito

Solicita el procesamiento de los datos enviados por {engine} (la clave de la engine viene del path). customer_uuid viene siempre de la credencial - cualquier valor en el cuerpo se ignora, igual que un campo engine en el cuerpo.

Formas de envío

  • application/json con filas inline: {"params": {...}, "data": [...]}.
  • multipart/form-data con un archivo .json/.csv/.parquet (detectado por magic bytes, nunca por el nombre) y un campo JSON params; los campos extra del form se fusionan en params como metadata.

Modos

Flags por query string (?sync=true, ?dry_run=true) o campos del cuerpo JSON. dry_run=true gana sobre sync=true.

ModoComportamientoÉxito
asíncrono (por defecto)Sube el input al almacenamiento, publica en la cola de la engine, retorna de inmediato202 {"process_uuid", "result_url"}
syncEl mismo publish más una espera directa acotada por el timeout del deploy (60s por defecto)200 {"process_uuid", "result"}
dry_runTotalmente efímero: nada se persiste en el almacenamiento de entrada, respuesta esperada200 {"process_uuid", "result"}

En un timeout de sync/dry_run la respuesta es 504 {"process_uuid": "..."} - guarda el process_uuid: el resultado aún puede llegar y consultarse en GET /api/v1/results/{process_uuid} (para dry_run esa consulta es de lectura única; ver burn-on-read).

Clasificación playground

playground=true marca la submisión como prueba - es clasificación, no modo: el job ejecuta exactamente igual (misma cola, mismo worker, misma precedencia dry_run > sync) y cuenta como uso en el reporte y el medidor; solo dry_run queda fuera. Lo que cambia es el registro: el listado de resultados puede entonces separar prueba de producción con el filtro playground.

Se acepta en los tres lugares, con el mismo patrón de sync/dry_run: query string (?playground=true), campo del cuerpo JSON y campo del multipart. El cuerpo gana sobre la query cuando ambos están presentes; ausente, vale false. La consola de esta documentación envía playground=true siempre, sin opción de apagarlo: lo que nace aquí es una prueba, y no contamina el registro de producción.

Engines aceptadas

El segmento {engine} del path debe ser una de las 105 engines del catálogo de la plataforma (11 grupos, ver GET /api/v1/catalog/engines). Las claves de engine del catálogo son la nomenclatura pública - enviar una clave interna responde 422, exactamente como una engine desconocida. Cinco engines de observabilidad, tracking_pages, tracking_sessions, tracking_visitors, edge_traffic y log_analyzer, se sirven bajo una clave pública distinta de la interna, y algunos campos de payload siguen la misma regla (first_tracking_id, last_tracking_id, tracking_id, log_query): la traducción se aplica en ambos bordes, params y el data inline se reescriben en el envío y los resultados vuelven ya en la nomenclatura pública. El contenido de un archivo subido pasa byte a byte y nunca se reescribe.

Orden de validación

Fail-fast: un envío rechazado no tiene ningún efecto secundario - nada se sube, nada se publica.

  • {engine} existe en el catálogo y está activa, si no 422.
  • {engine} está en allowed_engines de la suscripción (NULL = todas), si no 403.
  • La validación de params se delega al worker en tiempo de ejecución.
  • Subida dentro de max_upload_mb, si no 413.
  • Cuota diaria de jobs no excedida, si no 429.

Un cuerpo malformado responde 400.

Idempotencia

process_uuid es determinístico (UUID v5 del hash del contenido + engine + params canónicos, con namespace por tenant): reenviar contenido idéntico produce el mismo id, y la ingestión converge de forma idempotente.

Catálogo detallado por grupo

Cada engine de abajo acepta exactamente este endpoint (POST /api/v1/{engine}/process) con su propio contrato de params y data[]; el link abre la documentación completa, con tablas de campos y consola de ejemplo.

Analytics (15)

EngineClaveQué hace
Test A/Bab_testSignificancia de test A/B: z-test de dos proporciones o t-test de Welch, con análisis de poder.
Test A/B (rápido)ab_test_fastSignificancia de test A/B: z-test de dos proporciones (t-test continuo opcional).
Scorecard de afiliadosaffiliate_scorecardScorecard multidimensional de desempeño de afiliados/socios, con clasificación en tiers.
Atribución por canalchannel_attributionAtribución de canales de marketing con modelos last-touch, first-touch, linear o position-based.
Embudo de conversiónfunnelEmbudo de conversión estricto: conversión por etapa, abandono, usuarios perdidos y cuellos de botella.
Jornada (Markov)journey_markovAnálisis de matriz de transición en cadena de Markov sobre secuencias de etapas de jornada.
Jornada (Markov, rápido)journey_markov_fastAnálisis rápido de transiciones en cadena de Markov sobre secuencias de etapas de jornada.
Secuencias de jornadajourney_sequencesMinería de caminos frecuentes de jornada vía árbol de prefijos (Trie), con conversión por camino.
Atribución de marketingmarketing_attributionAtribución de canales de marketing con modelos last-touch, first-touch, linear o position-based.
Indicadores móvilesmoving_statsIndicadores de media móvil y volatilidad (SMA, EMA, WMA, Bollinger, ROC, YoY/MoM, CAGR) sobre una serie temporal.
Pareto & concentraciónparetoAnálisis de Pareto/concentración: coeficiente de Gini, HHI, curva de Lorenz, punto 80/20 y clasificación ABC.
Pipeline de enginespipelineMeta-engine que encadena varias engines en secuencia sobre el mismo conjunto de datos.
Estacionalidad (profunda)seasonality_deepDetección de estacionalidad por FFT con aceleración dedicada y descomposición tendencia/estacional/residuo.
Estacionalidad (FFT)seasonality_fftDetección de estacionalidad por FFT con descomposición en tendencia, estacional y residuo.
Atribución de Shapleyshapley_attributionAtribución de marketing multi-touch con valores de Shapley (teoría de juegos).

Inteligencia de Clientes (22)

EngineClaveQué hace
Churn (profundo)churn_deepPredicción de churn multi-modelo con aceleración dedicada (MLP, TabNet, Random Forest, XGBoost) y horizontes temporales.
Etiqueta de churnchurn_labelEtiquetado de churn por reglas determinísticas en tres modelos de negocio: ecommerce, saas, prepaid.
Predicción de churnchurn_predictionClasificación de churn con detección automática de features, selección de algoritmo por validación cruzada y métricas solo de holdout.
CLV (profundo)clv_deepPredicción de Customer Lifetime Value multi-modelo con aceleración dedicada (LSTM, MLP, XGBoost) en múltiples horizontes.
Análisis de cohortescohort_analysisTriángulo de retención por cohorte de adquisición (mensual o semanal).
Retención por cohortecohort_retentionMatriz de retención y tasas de churn por cohorte de adquisición (día, semana o mes).
Cliente 360customer_360Perfil compuesto del cliente que fusiona las sub-engines RFM, loyalty, features y etiqueta de churn en un único score de salud.
Clustering de clientescustomer_clusteringSegmentación de clientes con múltiples algoritmos de clustering y selección automática de K.
CLV del clientecustomer_clvCustomer Lifetime Value vía aproximaciones heurísticas BG/NBD + Gamma-Gamma basadas en RFM.
Features de CLVcustomer_clv_featuresExtracción de features BG/NBD + Gamma-Gamma por cliente (frecuencia, recencia, T, valor monetario) para modelado de CLV.
Migración de segmentoscustomer_migrationMatriz de transición de segmentos entre los dos períodos más recientes, con estado estacionario y proyección multi-período.
Velocidad de engagementengagement_velocityVelocidad y aceleración de engagement del cliente a partir de la cadencia de eventos y el gasto.
Features de clientesfeaturesIngeniería de features por cliente a partir del historial bruto de compras.
FidelidadloyaltyScore de fidelidad en tiers vía normalización MinMax ponderada de 5 métricas del cliente.
NPSnpsNet Promoter Score calculado a partir de respuestas 0-10 de encuesta.
Segmentos de comprapurchasing_segmentSegmentación de comportamiento de compra vía clustering multi-algoritmo con aceleración dedicada.
RFMrfmSegmentación RFM (Recencia, Frecuencia, Monetario) de clientes vía score por cuantiles.
Segmentación genéricasegmentSegmentación genérica de clientes vía clustering multi-algoritmo con aceleración dedicada.
Perfiles de clusterssegment_cluster_profilesPerfil estadístico y features discriminantes de cada cluster de clientes ya calculado.
Reporte de segmentaciónsegmentation_reportReporte consolidado de la distribución de clientes y métricas entre segmentos existentes.
Suscripciones & recurrenciasubscription_engineParámetros óptimos de suscripción/recurrencia por par cliente-producto.
Supervivencia (Kaplan-Meier)survival_kaplan_meierAnálisis de supervivencia Kaplan-Meier para estudios de vida útil del cliente / churn.

Financiero (6)

EngineClaveQué hace
Punto de equilibriobreak_evenAnálisis de punto de equilibrio: BEP en unidades/ingresos, margen de contribución, margen de seguridad, DOL y sensibilidad.
Monte Carlo (VAN)monte_carloSimulación Monte Carlo de VAN: distribución probabilística de VAN y TIR con VaR/CVaR y percentiles.
Monte Carlo (profundo)monte_carlo_deepSimulación Monte Carlo de VPN/TIR a gran escala con aceleración dedicada (fallback en CPU).
VPNnpvCalculadora de VPN: valor presente neto, TIR, payback fraccionario e índice de rentabilidad.
Cascada de ingresosrevenue_waterfallCascada de ingresos: descompone la variación de ingresos entre dos períodos en clientes nuevos/perdidos, frecuencia y ticket promedio.
Desempeño de ventassales_performanceDesempeño de ventas: ingresos por producto, cantidad, tendencia de ingresos, participación de mercado y margen de ganancia opcional.

Pronósticos (10)

EngineClaveQué hace
Pronóstico de costoscost_forecastingPronóstico de costos vía ExponentialSmoothing vs regresión lineal, con el mejor modelo elegido por RMSE en holdout.
Planificación de demandademand_planningPronóstico de demanda multi-SKU con ranking por volumen y alertas de tendencia.
Pronóstico de costos (CV)forecast_cost_improvedPronóstico de costos con validación cruzada de ventana expansiva, comparación por MAPE e intervalos de confianza.
Pronóstico de costos (dominio)forecast_cost_totusPronóstico de costos de dominio con ajuste de inflación opcional y detalle por categoría.
Pronóstico (profundo)forecast_deepPronóstico multi-horizonte con deep learning y aceleración dedicada (N-BEATS / N-HiTS, fallback MLP).
Pronóstico de ingresosforecast_revenuePronóstico de ingresos con crecimiento YoY y descomposición opcional volumen vs precio.
Pronóstico (modelo guardado)forecast_savedPronóstico con un modelo preentrenado cargado desde el almacenamiento de objetos, o fallback ExponentialSmoothing entrenado en la entrada.
Pronóstico de unidadesforecast_unitsPronóstico de unidades/demanda con detección de estacionalidad y clasificación de tendencia.
Pronóstico de unidades (lote)forecast_units_asyncioWrapper de sales_forecasting ruteable por callback para envíos en lote con metadatos de entrega asíncrona.
Pronóstico de ventassales_forecastingPronóstico de ventas multi-modelo (ExponentialSmoothing, ARIMA, tendencia lineal) con selección automática del mejor.

Inventario (9)

EngineClaveQué hace
Exceso de inventario (reporte)excess_inventory_nlpReporte de exceso de inventario: LLM primero, con fallback basado en reglas cuando el LLM no está disponible o falla.
Promoción por vencimientoexpiry_promoCalculadora de descuento óptimo de remarcación para productos próximos a vencer.
Optimizador entre sucursalesinter_branch_optimizerDetecta desequilibrios de stock entre sucursales por producto y recomienda transferencias.
Historial de inventarioinventory_historyAnálisis de movimientos de inventario por producto con 15+ métricas: rotación, volatilidad, clase ABC, aging FIFO y riesgo.
Optimización de inventarioinventory_optimizationCalculadora de EOQ y stock de seguridad con análisis de sensibilidad.
Exceso de inventario (LLM)nlp_llm_excess_inventoryReporte en lenguaje natural generado por LLM sobre exceso de inventario (resumen ejecutivo, principales ítems, aging, recomendaciones).
Predictor de recomprarefill_predictorPredice la fecha de la próxima recompra de productos de uso continuo a partir del historial de compras del cliente.
Aging de stockstock_agingClasifica los ítems de inventario en activos/lentos/muertos por días desde la última venta.
Reposición de stockstock_replenishmentCalcula stock de seguridad, punto de reposición, EOQ y clasificación de demanda por producto, con alertas de reposición.

Lenguaje Natural (8)

EngineClaveQué hace
Embeddings de imagenimage_embeddingsEmbeddings de imagen con aceleración dedicada: embed, similitud, búsqueda o dedup por modelo de visión.
LLMllmProcesamiento de texto por LLM en el tier de aceleración dedicada: sentimiento, resumen, clasificación, extracción, análisis, traducción o prompt custom.
Análisis de texto (EN)nlp_analisys_enAnálisis de texto por LLM fijado en inglés: sentimiento, resumen, clasificación, extracción, análisis o traducción al portugués.
Embeddings de textonlp_embeddingsEmbeddings semánticos de texto con aceleración dedicada: embed, similitud, búsqueda o clustering.
Análisis de textonlp_localAnálisis de texto vía LLM: sentimiento, resumen, clasificación, extracción, análisis, traducción o prompt custom.
Sanitización de PIIsanitizeRemoción de PII: enmascara emails, teléfonos, CPF/CNPJ, tarjetas de crédito e IPs en texto libre.
Sentimiento en tiempo realsentiment_realtimeSentimiento por reglas para micro-lotes: léxico + emojis + negación, sin LLM.
Voz del clientesentiment_vocAnálisis de voz del cliente vía LLM local (sentimiento, palabras clave o tópicos) con fallback por reglas.

Observabilidad (5)

EngineClaveQué hace
Accesos de bordeedge_trafficAnaliza logs de acceso del borde: clustering de IPs, jornadas de navegación, desempeño de backends y anomalías de seguridad.
Análisis de logslog_analyzerAnaliza logs de aplicación: frecuencia de errores, amenazas de seguridad y anomalías de errores inéditos.
Tracking de páginastracking_pagesClasifica páginas web por reglas de URL/título y construye un índice de búsqueda semántica.
Tracking de sesionestracking_sessionsDetecta jornadas de sesión anómalas por similitud de embeddings contra una baseline vectorial.
Tracking de visitantestracking_visitorsClasifica visitantes como humano, bot, scraper o crawler por similitud de embeddings más flags de señal.

Propensión (4)

EngineClaveQué hace
Propensión de comprapropensityScore de propensión de compra con aceleración dedicada vía competencia multi-modelo (Random Forest / XGBoost / red neuronal).
Propensión a campañapropensity_respond_campaignPropensión a responder a una campaña de marketing, vía XGBoost con aceleración dedicada y fallback en CPU.
Score de propensiónpropensity_scoreScore genérico de propensión a evento binario, con probabilidades calibradas y análisis de lift por deciles.
Propensión a upgradepropensity_upgrade_planPropensión a hacer upgrade de plan/tier, vía XGBoost con aceleración dedicada y fallback en CPU.

Recomendaciones (11)

EngineClaveQué hace
Score de bundlesbundle_scoringPuntúa pares candidatos de bundle de productos por lift de coocurrencia, soporte y precio sugerido de descuento.
Cross-sellcross_sellMatriz de coocurrencia de productos: soporte, confianza y lift para pares de cross-sell.
Precios dinámicosdynamic_pricingRecomendación de precio óptimo a partir de regresión log-log de elasticidad-precio.
Monitor de preciosprice_monitorMonitoreo competitivo de precios: PPI, tendencia, volatilidad, detección de guerra de precios y alertas de variación entre sitios.
Sensibilidad al precioprice_sensitivityCorrelación precio-demanda por producto y proxy de dirección de elasticidad.
Canasta de productosproduct_basketAnálisis de canasta de compras: itemsets frecuentes Apriori y reglas de asociación (soporte/confianza/lift).
Recomendación híbridarecommendEngine híbrida de recomendación: filtrado colaborativo SVD con aceleración dedicada y fallbacks por contenido y popularidad.
Recomendación de ítemsrecommend_itemsRecomendaciones por filtrado colaborativo vía factorización de matriz SVD (usuario-ítem o ítem-ítem).
Ítems similaresrecommend_similar_itemsRecomendaciones ítem a ítem: colaborativa (SVD+coseno) o por contenido, con aceleración dedicada opcional.
Modelo de upliftuplift_modelModelado de uplift T-Learner: efecto individual de tratamiento, segmentación de Radcliffe y Qini/AUUC.
Sugerencias de upsellupsell_suggestionsSugerencias de upsell rankeadas por lift de reglas de asociación, confianza o margen.

Riesgo (10)

EngineClaveQué hace
Anomalías (fraude)anomalyDetección de fraude/anomalías con aceleración dedicada vía competencia multi-algoritmo (Isolation Forest, LOF, autoencoder opcional).
Anomalías en cuentasanomaly_accountsDetección multidimensional de anomalías por Z-score sobre features numéricas por cuenta.
Anomalías (profundas)anomaly_deepDetección profunda de anomalías con aceleración dedicada vía VAE/DAGMM más baselines Isolation Forest y LOF.
Detección de anomalíasanomaly_detectionDetección no supervisada de anomalías vía Isolation Forest o Local Outlier Factor.
Anomalías en grafoanomaly_graphDetección de anomalías en redes de transacciones vía Z-scores de centralidad/PageRank.
Anomalías multivariadasanomaly_multivariateDetección multivariada de anomalías (Isolation Forest / LOF) para lotes grandes, con estadísticas univariadas opcionales por columna.
Anomalías (Z-score)anomaly_zscoreDetección univariada de anomalías por columna numérica: Z-score, IQR, MAD o Grubbs.
Riesgo de créditocredit_riskScore de riesgo de incumplimiento vía clasificadores calibrados Regresión Logística / Random Forest.
Riesgo de crédito (explicable)credit_risk_explainScore de riesgo de crédito explicable: importancia global por permutación más explicaciones de factores por muestra.
Detector de descuento falsofake_discount_detectorDetecta patrones fraudulentos de descuento en que los precios se inflan antes de la promoción para simular un descuento mayor.

Ventas & Tendencias (5)

EngineClaveQué hace
Matriz BCGbcg_matrixClasificación en matriz BCG de crecimiento-participación: Stars/Cash Cows/Opportunities/Problems.
Distribución por categoríacategory_distributionDetalle categórico genérico con conteos, porcentajes y tabulación cruzada opcional.
Análisis demográficodemographic_analysisDetalle demográfico de clientes por edad, género y afinidad género-categoría.
Preferencias de comprapurchase_preferencesAnálisis de preferencias de compra por categoría: horario, método de pago y día de la semana.
Distribución horariatime_distributionDistribución horaria de transacciones en rangos configurables, con detección de horas pico.
Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/rfm/process?dry_run=true&playground=true
AUTENTICACIÓN
X-TENANT-KEY
PATH PARAMS
engine

Cada engine exige sus propias columnas. Cambiar el engine aquí trae su payload de ejemplo al cuerpo de abajo.

QUERY PARAMS
sync
dry_run
playground
REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/rfm/process?dry_run=true&playground=true" \
  -H "X-TENANT-KEY: $TENANT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "params": { "bins": 5, "reference_date": "2026-08-01" }, "data": [ { "customer_id": "cloud-strife", "purchase_date": "2026-07-28", "amount": 1890 }, { "customer_id": "cloud-strife", "purchase_date": "2026-07-05", "amount": 1450 }, { "customer_id": "cloud-strife", "purchase_date": "2026-06-18", "amount": 1220 }, { "customer_id": "cloud-strife", "purchase_date": "2026-05-30", "amount": 980 }, { "customer_id": "ramza-beoulve", "purchase_date": "2026-07-30", "amount": 2100 }, { "customer_id": "ramza-beoulve", "purchase_date": "2026-07-11", "amount": 1680 }, { "customer_id": "ramza-beoulve", "purchase_date": "2026-06-24", "amount": 1340 }, { "customer_id": "ramza-beoulve", "purchase_date": "2026-06-02", "amount": 1105 }, { "customer_id": "tifa-lockhart", "purchase_date": "2026-07-19", "amount": 640 }, { "customer_id": "tifa-lockhart", "purchase_date": "2026-06-28", "amount": 585 }, { "customer_id": "tifa-lockhart", "purchase_date": "2026-06-06", "amount": 520 }, { "customer_id": "tifa-lockhart", "purchase_date": "2026-05-14", "amount": 610 }, { "customer_id": "agrias-oaks", "purchase_date": "2026-07-22", "amount": 720 }, { "customer_id": "agrias-oaks", "purchase_date": "2026-06-30", "amount": 665 }, { "customer_id": "agrias-oaks", "purchase_date": "2026-05-27", "amount": 590 }, { "customer_id": "barret-wallace", "purchase_date": "2026-07-15", "amount": 3250 }, { "customer_id": "cidolfas-orlandeau", "purchase_date": "2026-06-21", "amount": 2980 }, { "customer_id": "cidolfas-orlandeau", "purchase_date": "2026-03-09", "amount": 2400 }, { "customer_id": "cid-highwind", "purchase_date": "2026-03-12", "amount": 880 }, { "customer_id": "cid-highwind", "purchase_date": "2026-02-20", "amount": 940 }, { "customer_id": "cid-highwind", "purchase_date": "2026-01-28", "amount": 760 }, { "customer_id": "delita-heiral", "purchase_date": "2026-02-14", "amount": 1120 }, { "customer_id": "delita-heiral", "purchase_date": "2026-01-19", "amount": 1050 }, { "customer_id": "yuffie-kisaragi", "purchase_date": "2026-01-09", "amount": 180 }, { "customer_id": "mustadio-bunansa", "purchase_date": "2026-01-15", "amount": 215 }, { "customer_id": "mustadio-bunansa", "purchase_date": "2026-01-03", "amount": 160 } ] }'

Listar resultados

Compartir
GET/api/v1/results
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

Resúmenes paginados (más recientes primero), con alcance del tenant, en el envelope de paginación estándar. Los resultados efímeros (dry_run) nunca aparecen aquí, con o sin filtros.

Parámetros de query

ParámetroSignificado
pageNúmero de página, 1-based. Por defecto 1
per_pagePor defecto 50, máximo 200
engineFiltra por nombre de engine
statuscompleted o failed
from / toLímites de created_at (RFC 3339, inclusivos)
includesummary trae el payload compacto en cada fila
playgroundtrue lista solo lo que nació clasificado como playground; false lista el resto, incluidos los jobs que la API nunca vio nacer (publicados directo en el broker), que cuentan como no-playground. Ausente, lista todo
paginatecursor devuelve el cuerpo keyset (obsoleto)

Un parámetro fuera de esta tabla responde 400, nunca se ignora en silencio: ?stauts=failed devolvería el listado entero, que la pantalla lee como "esta empresa no tiene fallos".

Respuesta

{
  "current_page": 2,
  "data": [
    { "process_uuid": "0c099b32-f000-48d0-92d7-dfe4a6f33def", "engine": "rfm",
      "status": "completed", "execution_ms": 1432, "created_at": "2026-08-27T18:22:31Z" }
  ],
  "first_page_url": "/api/v1/results?engine=rfm&page=1&per_page=50",
  "from": 51,
  "last_page": 4,
  "last_page_url": "/api/v1/results?engine=rfm&page=4&per_page=50",
  "links": [
    { "url": "/api/v1/results?engine=rfm&page=1&per_page=50", "label": "&laquo; Previous", "active": false },
    { "url": "/api/v1/results?engine=rfm&page=2&per_page=50", "label": "2", "active": true },
    { "url": "/api/v1/results?engine=rfm&page=3&per_page=50", "label": "Next &raquo;", "active": false }
  ],
  "next_page_url": "/api/v1/results?engine=rfm&page=3&per_page=50",
  "path": "/api/v1/results",
  "per_page": 50,
  "prev_page_url": "/api/v1/results?engine=rfm&page=1&per_page=50",
  "to": 100,
  "total": 187
}

from y to son posiciones 1-based dentro del conjunto entero, y vienen null cuando la página está vacía - no 0. total cuenta todas las filas que coinciden con los filtros. links trae el pager ya renderizado, incluidos los ... donde se elidió un tramo, y cada link repite los filtros vigentes: seguirlo nunca amplía el conjunto sin avisar.

execution_ms y error se omiten cuando no aplican. created_at es el instante de finalización, no el de envío.

Las URLs pueden ser relativas

path y los *_url son absolutos solo cuando el despliegue define PUBLIC_BASE_URL; sin él salen relativos a la raíz (/api/v1/results?page=2). Es deliberado: el servicio se niega a derivar su propia URL del header Host, que detrás de un proxy inverso es un valor que el cliente controla. Resuelva con new URL(url, base) en vez de concatenar, o arme la navegación a partir de current_page y last_page.

include=summary

Sin él, una pantalla que muestra lo que produjo cada job necesita un GET /api/v1/results/{process_uuid} por fila - cincuenta y una peticiones para una página de cincuenta, contra la misma cuota por minuto que gasta el resto de la integración. Con él, cada fila trae result_summary y la página entera cuesta una petición.

Es opt-in porque quien lista solo para seguir el estado no usa el payload y no debe pagarlo en bytes. Los links de paginación repiten la flag, así que la página dos no cambia de forma a mitad de la navegación. El payload completo sigue en la ruta de detalle.

Paginación keyset (obsoleta)

?paginate=cursor - o cualquier petición que ya envíe ?cursor= - devuelve el cuerpo original {"items": [...], "next_cursor": "..."}, con limit en lugar de per_page y next_cursor ausente en la última página. Un cursor inválido responde 400; nunca se trata como primera página.

Sigue siendo la herramienta correcta para recorrer el historial entero: un cursor cuesta lo mismo a cualquier profundidad, mientras que page se rechaza más allá de 100.000 filas adentro. Tampoco se desliza - filas que llegan a mitad del recorrido nunca hacen que los ítems se repitan o desaparezcan.

Regla práctica: una pantalla paginada usa page; exports y recorridos completos usan paginate=cursor.

Errores

StatusCuándo
400parámetro desconocido, page menor que 1 o más allá de 100.000 filas, cursor inválido
429ventana de peticiones por minuto agotada
Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/results?page=1&per_page=50&engine=rfm
AUTENTICACIÓN
X-TENANT-KEY
QUERY PARAMS
page
per_page
engine
status
from
to
include
playground
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/results?page=1&per_page=50&engine=rfm" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Detalle de resultado

Compartir
GET/api/v1/results/{process_uuid}
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

El detalle completo de un resultado, con alcance del tenant. Un process_uuid que no existe, pertenece a otro tenant o ya fue quemado responde 404 (nunca 403 - la existencia no se filtra).

Cuerpo

process_uuid, engine, status, params (como fueron aceptados), result_summary (siempre inline), execution_ms (cuando está presente), ephemeral, created_at, más exactamente uno de:

  • Payload inline: result_full presente, result_full_url ausente.
  • Payload con claim-check (resultados grandes van al almacenamiento de objetos): result_full ausente y result_full_url con una URL de descarga prefirmada de vida corta (300s por defecto). Descárgala pronto; repite la llamada para obtener una URL nueva.

En jobs fallidos, error lleva el motivo.

Los efímeros son burn-on-read

Un resultado dry_run se borra atómicamente en el primer GET exitoso, que lo devuelve; toda request siguiente responde 404. Exactamente un llamante observa un resultado efímero, incluso bajo lecturas concurrentes. Las filas efímeras no leídas expiran en 1 día.

Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/results/{process_uuid}
AUTENTICACIÓN
X-TENANT-KEY
PATH PARAMS
process_uuid
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/results/{process_uuid}" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Uso agregado

Compartir
GET/api/v1/results/stats
Auth
X-TENANT-KEY o Authorization: Bearer
Base
https://intelligence.echosistema.live

Propósito

Conteos, reparto de fallos y percentiles de duración de la empresa autenticada, abiertos por tiempo, por engine y por flota de workers - lo que necesita un panel de uso, en una sola llamada.

Usa esto en vez de paginar el listado para contar. Noventa días de una empresa con movimiento son cientos de peticiones contra la misma cuota por minuto que gasta el resto del producto, repetidas en cada carga del panel.

Parámetros

ParámetroSignificado
from, toRFC 3339, inclusivos. Por defecto, los últimos 30 días. Ventana limitada a 366 días
bucketday (por defecto), week o month - granularidad de la serie
enginerecorta todas las secciones a un engine
statusrecorta todas las secciones a completed o failed

Respuesta

{
  "from": "2026-06-01T00:00:00Z",
  "to": "2026-08-27T18:00:00Z",
  "bucket": "week",
  "totals": { "count": 4821, "completed": 4760, "failed": 61, "p50_ms": 340, "p95_ms": 18200 },
  "series": [{ "bucket": "2026-06-01T00:00:00Z", "count": 190, "completed": 188, "failed": 2 }],
  "engines": [{ "engine": "rfm", "runtime": "rust", "category": "analytics", "count": 1200, "failed": 3, "p50_ms": 12, "p95_ms": 45 }],
  "runtimes": [{ "runtime": "gpu", "count": 310, "failed": 12, "p50_ms": 41000, "p95_ms": 92000 }]
}

Cuatro cosas antes de graficar

Todas las secciones salen de una transacción, sobre la misma ventana: los totales nunca discrepan de la suma de los desgloses.

Los percentiles no son aditivos. El p95 de una flota no se arma con el p95 de sus engines - cada uno se mide sobre la ventana que describe.

Los buckets vacíos están ausentes, no en cero. La API informa lo que ocurrió; un gráfico que necesita eje continuo rellena los huecos con el rango que ya pidió.

runtimes puede sumar menos que totals. Un engine que se ejecutó y luego salió del catálogo conserva su uso en engines, sin runtime, pero no se atribuye a una flota que quizá no lo ejecutó.

Errores

StatusCuándo
400from posterior a to, o ventana mayor de 366 días
429ventana de peticiones por minuto agotada

Los resultados dry-run se excluyen, igual que en el listado - un dry-run no es uso. Las duraciones son el tiempo de ejecución del worker, no la espera en cola, que este servicio no observa.

El bloque payload: lo que fue enviado

Las otras secciones describen lo que volvió. Esta describe lo que el cliente envió, medido en el instante en que la submission fue aceptada.

CampoSignificado
submissionsCuántas submissions tiene la ventana, medidas o no
bytes_totalSuma del input medido
bytes_avgMedia del input medido
bytes_p50, bytes_p95Mediana y percentil 95. No son aditivos

Como el registro nace en la aceptación y no en la conclusión, cuenta también los jobs que nunca produjeron resultado: consumieron la subida, la cola y un worker igual, y quitarlos describiría un consumo menor que el real.

El bloque está ausente cuando nada en la ventana fue medido. Eso es distinto de cero bytes: un tenant cuyas submissions son anteriores a la medición, o que solo corrió dry-run, se queda sin respuesta aquí en vez de recibir una respuesta de nada.

Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/results/stats?bucket=day
AUTENTICACIÓN
X-TENANT-KEY
QUERY PARAMS
bucket
engine
status
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/results/stats?bucket=day" \
  -H "X-TENANT-KEY: $TENANT_KEY"

En vuelo

Compartir
GET/api/v1/submissions/pending
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

Lo que esta empresa envió y todavía no recibió de vuelta, del que espera hace más tiempo al que espera hace menos.

Pendiente no es un estado del listado, y no podría serlo. GET /api/v1/results lee la tabla de los resultados, y un resultado guardado es terminal: completed o failed. Un job aceptado y todavía en proceso no tiene fila alguna allí, así que ?status=pending sería pedirle a una tabla que describa lo que deliberadamente no registra. Esta ruta lee otra cosa: el registro del envío, escrito en el instante en que fue aceptado.

Parámetros de query

ParámetroSignificado
stale_afterSolo los que esperan hace más que esos segundos. Ausente devuelve todos. Negativo responde 400
engineUn engine, en la grafía actual o en la heredada
limitPredeterminado y tope 200

Respuesta

200 con {"pending": [...], "count": 1, "queues": [...]}, del que espera hace más tiempo al que espera hace menos.

{
  "pending": [
    { "process_uuid": "0c099b32-f000-48d0-92d7-dfe4a6f33def", "engine": "rfm", "mode": "async",
      "submitted_at": "2026-08-28T04:10:00Z", "waiting_secs": 3600,
      "queue": "ml.customer_intelligence.rfm" }
  ],
  "count": 1,
  "queues": [{ "engine": "rfm", "waiting": 4213, "consumers": 6 }]
}
CampoQué es
pending[].process_uuidEl mismo identificador que devolvió el envío, y el que tendrá el resultado
pending[].engineEl engine, en la grafía pública
pending[].modeasync o sync
pending[].submitted_atCuándo fue aceptado el envío (RFC 3339)
pending[].waiting_secsHace cuántos segundos espera
countCuántas filas llegaron
queues[]El estado de las colas de esos engines, ausente cuando no se pudo obtener

Tres cosas que se equivocan solas aquí

No existe umbral predeterminado, y es a propósito. El tiempo que vuelve sospechosa una espera depende del engine: un rfm de doce milisegundos y un job pesado de cinco minutos no comparten número. Cada fila trae waiting_secs y quien llama juzga. Un umbral fijo escrito en el cliente y presentado como "atrasado" es una afirmación que esta ruta no hace.

queues describe la operación entera, nunca tu fila. Ahí están cuántos mensajes esperan y cuántos procesos los escuchan, sumando todas las empresas: atribuir un mensaje a un cliente exigiría consumirlo. Esos números responden "este engine está congestionado, hay alguien trabajando en él", y nunca "mi job es el 4213º de la fila".

queues ausente es respuesta no obtenida, y no fila vacía. El contexto tiene un presupuesto de tres segundos y nunca retiene la respuesta: la lista llega igual. consumers: 0 es el único valor accionable, y significa que nada avanza para ese engine mientras no vuelva alguien a procesarlo.

Cuándo una submission sale de esta lista

En el instante en que su resultado se guarda. Ambas escrituras ocurren en la misma transacción, así que nunca hay un resultado guardado que siga apareciendo aquí - no existe ventana en que las dos rutas se contradigan.

La marca vive en la propia submission, y eso es lo que la hace estable en el tiempo: cada plan guarda los resultados por menos tiempo que las submissions (retention_days), y un resultado barrido no hace que su submission reaparezca como pendiente.

Errores

StatusCuándo
400stale_after negativo
429ventana de solicitudes por minuto agotada

Dry-run nunca aparece: su resultado se lee una vez y desaparece, y quedaría aquí para siempre con cara de trabado.

Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/submissions/pending
AUTENTICACIÓN
AuthorizationBearer

Esta ruta acepta solo el token: una clave de API nombra a una empresa, no a una persona, y se rechaza con 401 aunque sea válida.

QUERY PARAMS
engine
limit
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/submissions/pending" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Catálogo de engines

Compartir
GET/api/v1/catalog/engines
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

El catálogo completo de engines aceptadas, agrupado por los once grupos de la plataforma (analytics, customer_intelligence, financial, forecast, inventory, nlp, observability, propensity, recommendations, risk, sales_trends), con un flag allowed calculado desde tu suscripción.

Respuesta

200 con {"groups": [{"group": "...", "engines": [{"engine", "runtime", "active", "allowed"}]}], "total": 105}.

runtime es una clasificación interna del tier de ejecución de la engine; los nombres de cola y la topología interna no se exponen.

Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/catalog/engines
AUTENTICACIÓN
X-TENANT-KEY
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/catalog/engines" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Engines con resultados

Compartir
GET/api/v1/engines
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

Las engines distintas que tienen al menos un resultado (no efímero) para el tenant autenticado: {"engines": ["kmeans", "rfm"]}.

Es el complemento del catálogo: el catálogo dice qué puedes correr; esta ruta dice qué ya corriste.

Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/engines
AUTENTICACIÓN
X-TENANT-KEY
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/engines" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Salud de la flota

Compartir
GET/api/v1/platform/health
Auth
credencial de tenant o token de operador

Propósito

La salud agregada de la flota de ejecución. Dos señales se combinan por tier de ejecución: el heartbeat más fresco de cada worker y la presencia de consumidores en las colas del tier. Los tiers esperados vienen de las filas activas del catálogo de engines, nunca de una lista fija.

StatusSignificado
healthyHeartbeat más nuevo que 90s Y al menos un consumidor coincidente
degradedHeartbeat de 90-300s, O las dos señales discrepan (heartbeat fresco, cero consumidores)
downHeartbeat de más de 300s (o nunca visto) Y ningún consumidor, para un tier esperado
disabledEl tier no tiene engine activa en el catálogo - informativo, sin alarma

Una indisponibilidad de la API de gestión de colas nunca tumba el endpoint: la señal de consumidores reporta "unknown" y el status cae a la vista solo de heartbeat.

Forma de acceso (protección de topología)

Una credencial de tenant recibe solo {"runtimes": {"py": {"status": "healthy"}, ...}} - sin nombres de cola, identidades de worker ni conteos. El token de operador recibe además la edad del heartbeat, los consumidores y la lista por worker.

GET /healthz sigue siendo un probe de liveness separado, sin autenticación y sin dependencias.

Probar solicitudOPENAPI
GET
https://intelligence.echosistema.live/api/v1/platform/health
AUTENTICACIÓN
X-TENANT-KEY
Envía la solicitud para ver la respuesta.
curl
curl -X GET "https://intelligence.echosistema.live/api/v1/platform/health" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Límites y cuotas

Compartir
Auth
aplicados a toda ruta autenticada

Cómo funcionan

  • Por minuto (max_requests_per_min): ventana fija de minuto UTC en toda ruta autenticada. Excederla responde 429. /healthz nunca se limita.
  • Por día (max_jobs_per_day): ventana fija de día UTC, verificada dentro de POST /api/v1/{engine}/process antes de cualquier efecto secundario; excederla responde 429.
  • NULL en la suscripción desactiva ese límite específico.

Los valores vigentes de tu suscripción aparecen en GET /api/v1/auth.

Registrar dispositivo

Compartir
POST/api/v1/devices
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

Registra un dispositivo para recibir notificaciones push del tenant autenticado. Todo usuario del tenant recibe la alerta de todo job terminado del tenant (no hay suscripción por usuario).

Cuerpo

{"platform": "ios", "registration_id": "cX9_f-Yz:APA91bH..."}

  • platform es uno de android, ios, web.
  • registration_id es el token de registro/instalación del servicio de push: 16 a 4096 bytes, solo ASCII gráfico imprimible (sin espacio, sin caracteres de control). Cualquier otra cosa responde 400 {"error": "invalid registration_id"}. Los campos desconocidos se rechazan.

El tenant viene de tu credencial y nunca puede enviarse en el cuerpo.

Respuesta

Responde 200 siempre, nunca 201 - el registro es un upsert. Volver a registrar el mismo dispositivo devuelve el mismo id y refresca su último contacto; registrar un dispositivo que hoy pertenece a otro tenant lo mueve al tuyo atómicamente, y el dueño anterior deja de recibir por él de inmediato (un aparato que cambió de manos no puede seguir recibiendo las alertas de la cuenta vieja).

{"id": 42, "platform": "ios", "active": true, "last_seen_at": "2026-08-20T12:00:00Z"}

El registration_id nunca se devuelve: ya lo tienes, y la respuesta sería un lugar más por donde filtrarse. Los dispositivos se direccionan por el id de aquí en adelante.

Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/devices
AUTENTICACIÓN
X-TENANT-KEY
REQUEST BODY · JSON
Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/devices" \
  -H "X-TENANT-KEY: $TENANT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "platform": "ios", "registration_id": "cX9_f-Yz:APA91bH-exemplo" }'

Quitar dispositivo

Compartir
DELETE/api/v1/devices/{id}
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

Detiene la entrega a un dispositivo, por el id de la respuesta de registro. Responde 204, y 204 de nuevo en una segunda llamada (idempotente). Un dispositivo que no existe y uno de otro tenant responden ambos 404 - la existencia no se filtra.

Es un soft delete: el registro permanece para auditoría y simplemente deja de ser un destino. El servicio hace la misma desactivación por sí solo cuando el proveedor de push reporta el registro como muerto (app desinstalada, token rotado) - un dispositivo abandonado sale del fan-out sin ninguna llamada tuya.

Probar solicitudOPENAPI
DELETE
https://intelligence.echosistema.live/api/v1/devices/42
AUTENTICACIÓN
X-TENANT-KEY
PATH PARAMS
id
Envía la solicitud para ver la respuesta.
curl
curl -X DELETE "https://intelligence.echosistema.live/api/v1/devices/42" \
  -H "X-TENANT-KEY: $TENANT_KEY"

Ticket de realtime

Compartir
POST/api/v1/realtime/tickets
Auth
X-TENANT-KEY o Authorization: Bearer

Propósito

Emite un ticket de un solo uso para abrir el WebSocket de realtime. Sin cuerpo de request: el tenant viene de la credencial, como en GET /api/v1/auth y /me.

Respuesta

{"ticket": "9f2c... 64 caracteres hex minúsculos ...", "expires_in": 45}

expires_in está en segundos relativos, no es un timestamp absoluto - el ticket es para uso inmediato, sin husos horarios ni clock skew que reconciliar.

Por qué existe

El new WebSocket() de un navegador no puede enviar un header custom, así que ni X-TENANT-KEY ni Bearer viajan en el handshake. El ticket cubre exactamente esa brecha: es opaco, de vida corta, atado a tu tenant y consumido por el primer upgrade exitoso. Presentarlo una segunda vez falla como un ticket que nunca existió.

Trátalo como credencial, no como identificador: viaja en query string, así que asegúrate de que tu reverse proxy no escriba la query string del upgrade en su access log.

Dos comportamientos de la v1 que vale saber: emitir un ticket nuevo no invalida uno que ya tengas, y cada emisión cuenta contra tu cuota de requests por minuto.

Probar solicitudOPENAPI
POST
https://intelligence.echosistema.live/api/v1/realtime/tickets
AUTENTICACIÓN
X-TENANT-KEY
Envía la solicitud para ver la respuesta.
curl
curl -X POST "https://intelligence.echosistema.live/api/v1/realtime/tickets" \
  -H "X-TENANT-KEY: $TENANT_KEY"

WebSocket realtime

Compartir
Ruta
GET /api/v1/realtime/ws?ticket={ticket}
Auth
ticket de POST /api/v1/realtime/tickets en la query string

Propósito

Hace el upgrade al WebSocket de realtime. No hay otra credencial, porque un handshake de navegador no puede llevar headers.

El socket es unidireccional: el servidor transmite frames y nada de lo que envíes se procesa. Todo frame es JSON y lleva su versión de contrato dentro del frame:

  • {"version": 1, "event": "result", "process_uuid": "5d1c...", "status": "completed"}
  • {"version": 1, "event": "heartbeat"}

Un frame result lleva identificadores y una etiqueta de status y nada más - sin nombre de engine, sin resumen, sin fragmento del resultado. Busca lo que necesites con GET /api/v1/results/{process_uuid}: esa llamada es autenticada y con alcance de tenant, lo que el payload del socket deliberadamente no intenta ser. Los campos ausentes se omiten, nunca se envían como null.

Rechazos

StatusSignificado
400No es un upgrade WebSocket válido
401Ticket ausente, desconocido, expirado, ya usado, o el tenant ya no está activo. Todos responden de forma idéntica - la respuesta nunca revela cuál
404El canal de realtime está deshabilitado en este deploy
429Tu ventana de requests por minuto se agotó. Espera y pide un ticket nuevo
503Esta réplica está en su techo de conexiones. No es tu límite: reintenta en breve

Para construir encima

Un rechazo después de que el ticket fue leído ya lo consumió - el reintento es pedir un ticket nuevo, nunca volver a presentar el viejo. Y la entrega es best effort: si la conexión cae, o el cliente deja de leer hasta llenar su buffer, los frames se descartan y nunca se reentregan - recarga la vista y apóyate en el push o en GET /api/v1/results para lo que no puede perderse.

El servidor cierra el socket con 4000 ("session expired, reconnect") cuando alcanza su tiempo máximo de vida, y con 4001 ("authorization revoked") cuando el tenant es suspendido o la suscripción queda inactiva. Trata los dos de forma distinta: 4000 es reconectar, 4001 es detenerse y arreglar la cuenta.

Webhook de finalización

Compartir
Dirección
la API te llama A TI
Config
webhook_url / webhook_secret / webhook_events del tenant

Propósito

Cuando el tenant tiene webhook configurado, el servicio hace un POST de notificación después de que un resultado no efímero se persiste, si el desenlace coincide con webhook_events (completed, failed o both).

La entrega es at-least-once. Deduplica por process_uuid de tu lado - una reentrega del broker puede ocasionalmente producir una segunda notificación del mismo job.

Cuerpo

{"process_uuid": "...", "engine": "rfm", "status": "completed", "execution_ms": 42, "result_url": "/api/v1/results/<process_uuid>", "summary": {"score": 0.87}}

result_url es el endpoint estable de la API (únelo a la base de la API), nunca un link prefirmado de vida corta - vale cuando vayas a buscarlo.

Firma

Header X-Intelligence-Signature: sha256=<hexdigest>, donde el digest es HMAC-SHA256(bytes exactos del cuerpo crudo, webhook_secret). Verifica recomputando el HMAC sobre los bytes crudos recibidos (nunca sobre un parse reserializado) y compara en tiempo constante.

Entrega

Reintentos: 3 intentos en total, 1s antes del 2º, 3s antes del 3º, timeout de 5s por intento. Las URLs de destino deben resolver a direcciones públicas; los rangos privados, loopback, link-local y de metadatos se rechazan.

Push (contrato)

Compartir
Dirección
la plataforma notifica a los dispositivos registrados
Registro
POST /api/v1/devices

El contrato

El push no lleva datos de negocio, y eso es contrato, no detalle de implementación.

El texto visible de la alerta es uno de tres strings fijos (PT / EN / ES, según el idioma por defecto del tenant). No contiene nombre de engine, número, nombre de archivo ni fragmento de resultado, porque se renderiza fuera de tu app, en una pantalla de bloqueo, por software que no es nuestro y que cualquiera con el teléfono en la mano puede leer.

El bloque data lleva exactamente tres strings:

{"process_uuid": "...", "status": "completed", "result_url": "https://intelligence.echosistema.live/api/v1/results/..."}

result_url se construye desde la configuración del servidor, nunca desde el header Host de request alguna, y es el endpoint estable de la API, no un link de vida corta. Busca el resultado con tu llamada autenticada normal; la notificación es un timbre, no una entrega.

El cuerpo del webhook no es plantilla para el push. Lleva summary (datos reales del resultado) porque viaja a TU infraestructura por HTTPS con firma HMAC. El push pasa por un tercero y aparece en una pantalla de bloqueo - copiar el payload del webhook al push es un defecto de seguridad, no una optimización.

Higiene automática

Los dispositivos se desactivan automáticamente cuando el proveedor de push reporta el registro como muerto (app desinstalada, token rotado) y se depuran tras la ventana de inactividad del deploy. Ninguna de las dos necesita una llamada tuya.

Los tres canales, lado a lado

Tres canales anuncian el mismo evento y ninguno reemplaza a otro. Elige por dónde está el usuario, no por preferencia.

SituaciónWebhookPushRealtime
Tu backend necesita el resultado - firmado, con retry, durablenono
App cerrada, teléfono en el bolsillono - la alerta despierta el dispositivono
App abierta en la pantalla del jobno(también dispara) - llega en milisegundos
El usuario está offline ahoraentregado a tu servidor igualentregado cuando el dispositivo vuelvaperdido, por diseño
Garantía at-least-oncesí, mientras el dispositivo sea alcanzableno

Un job enviado con ?sync=true se anuncia como cualquier otro - el modo no deja marca en la fila persistida, lo que mantiene correcto el caso del 504: un envío sync que agotó el tiempo aún necesita su notificación cuando el resultado finalmente llegue. Por eso, deduplica por process_uuid en todos los canales.

Entrar

Usa tu cuenta EchoSistema para seguir tus integraciones.