PandoraAPIv1.0.424Configuraciónopenapi.jsonPanel

Pandora Cloud API v1.0.424

Pandora Cloud es una plataforma de observabilidad multi-tenant. Su API permite integrarla desde fuera y cubre dos modelos complementarios:

  • Monitorización activa: creas y consultas chequeos (web, ping, puerto, certificado SSL, caducidad de dominio, DNS, API/JSON). Pandora Cloud las sondea periódicamente y registra estado, latencia, eventos e incidencias.
  • Señales pasivas (push): procesos, scripts y agentes dejan su estado en una señal. Sirve para saber si algo se está ejecutando en cualquier sistema, incluido el progreso de tareas de agentes de IA (p. ej. opencode).
Base URL http://eu01.cloud.pandorafms.com/api/v1 · Formato JSON · Autenticación Bearer por tenant · Versión v1

Esta página es la guía; la especificación completa (esquemas, parámetros y respuestas de cada operación) es openapi.json. Las rutas y la especificación están sincronizadas por un test de contrato.

Autenticación

Cada tenant tiene uno o varios tokens. Envíalo en la cabecera Authorization. Puedes verlo o regenerarlo en Configuración.

curl -H "Authorization: Bearer pc_TU_TOKEN" http://eu01.cloud.pandorafms.com/api/v1/me

Sin token válido: 401. El token da acceso únicamente a los datos de su tenant: no hay forma de leer ni escribir datos de otro.

Las vistas compartidas (enlaces de solo lectura) no usan la API: son páginas públicas con su propio token de sólo lectura.

Login por API y acceso directo (integración)

Además del token de tenant, la API ofrece autenticación por email+contraseña y un enlace de un solo uso para abrir el panel ya logueado (lo usa Pandora MINI).

LlamadaQué hace
POST /v1/auth/register (Cloud Master)Público. Crea la cuenta (asigna nodo) y devuelve node_url y email_verified:false. El nodo envía el correo de verificación.
POST /v1/auth/loginPúblico. {"email","password","totp"} → token de usuario (pc_…). 403 email_not_verified si el email no está validado; 401 totp_required si falta el 2FA.
POST /v1/auth/ssoCon Bearer: devuelve {"url","expires_in"}, un enlace de un solo uso (60 s) para entrar al panel ya logueado (GET /login/sso?t=…).
GET /verify?t=…(Web) Consume el token del correo y marca el email como verificado.

GET /me incluye user (id, email, email_verified) y agent (group_key, group_password, tentacle_host, tentacle_port).

Conceptos

ConceptoQué es
TenantEspacio aislado. Cada token pertenece a un tenant.
Monitorización (host / agente)Agrupa uno o varios chequeos (una web, un servidor, un correo…). En la interfaz la llamamos agente.
Chequeo (activa)Pandora Cloud la sondea (pull). Genera estado, eventos e incidencias.
Módulo (de endpoint)Un chequeo de un agente Pandora (kind=agent): no lo sondea la plataforma, lo envía el endpoint. Ver Agentes Pandora.
Señal (pasiva)El emisor empuja su estado (push). Se identifica por emisor + signal_id y guarda la última muestra: no acumula histórico.
EmisorQuién publica: opencode@mac-slerena, cron@srv-01. Es la primera parte de la clave.
AgenteLa monitorización a la que se ancla la señal (agent_id, el id interno). Si lo omites, se ancla por el agent_name (Endpoint Name) del emisor; si no hay endpoint con ese nombre, se crea uno.
Criticidadok, warning, critical o unknown. El sistema añade dead (muda demasiado tiempo) y stale.
Ciclo de vidaqueued, running, waiting, done, error, cancelled.
Keepaliveinterval + keepalive: si una señal periodic deja de llegar, pasa a dead.
shapestatic, dynamic o fluid: qué puede comparar el sistema con la muestra anterior (deltas, altas y bajas de filas).
EventoRegistro de cada cambio de estado. Visible en la consola de eventos.
IncidenciaUna caída confirmada. Puede notificar por email, Discord, Telegram, SMS, llamada de voz, Slack, Teams o webhook.
AvisoLa notificación por tus canales. Se dispara por umbral, por reconexión o por incidencia abierta. Ver Avisos y repetición.

La señal no guarda histórico. Para tendencias, publica métricas con POST /metrics y referéncialas desde un panel ("options":{"metric":"…"}). Es la única vía a gráficas de meses, y además mantiene la muestra pequeña.

Inicio rápido

# 1) La API responde (público)
curl http://eu01.cloud.pandorafms.com/api/v1/ping

# 2) Tu tenant, tus cuotas y el catálogo de tipos de chequeo
curl -H "Authorization: Bearer pc_TU_TOKEN" http://eu01.cloud.pandorafms.com/api/v1/me

# 3) Crear una chequeo web (crea/reutiliza la monitorización "Mi web")
curl -X POST http://eu01.cloud.pandorafms.com/api/v1/checks \
  -H "Authorization: Bearer pc_TU_TOKEN" -H "Content-Type: application/json" \
  -d '{"host":"Mi web","kind":"https","target":"example.com","params":{"contains":"Bienvenido"}}'

# 4) Publicar una señal (push): emisor y señal, en la ruta
curl -X PUT http://eu01.cloud.pandorafms.com/api/v1/signals/opencode/mi-tarea \
  -H "Authorization: Bearer pc_TU_TOKEN" -H "Content-Type: application/json" \
  -d '{"spec":"pandora.signal/v1",
       "signal":{"name":"Mi tarea","mode":"periodic","interval":300,"keepalive":120},
       "sample":{"seq":1,"status":"ok","lifecycle":"running","summary":"arrancando"},
       "data":{"fase":"links","cola":12}}'

# 5) Publicar una métrica propia
curl -X POST http://eu01.cloud.pandorafms.com/api/v1/metrics \
  -H "Authorization: Bearer pc_TU_TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"cpu.load","value":0.42,"unit":"%","tags":{"host":"srv1"}}'

Endpoints

Los cuerpos y las respuestas de las operaciones principales se detallan en las secciones siguientes; la especificación completa, con todos los parámetros y esquemas, es openapi.json.

System
MétodoRutaDescripción
GET/v1/countsConteo de estados (ok/aviso/caído/sin datos) e incidencias abiertas.
GET/v1/meDatos del tenant, cuotas, identidad del usuario y datos de conexión del agente.
PATCH/v1/meModifica ajustes de notificaciones (qué severidades abren incidencia).
GET/v1/pingComprueba que la API responde (público).
GET/v1/resolveResuelve un nombre a sus IP públicas (ayuda para el chequeo DNS).
GET/v1/searchBúsqueda global: agentes, monitores, métricas y fuentes de logs.
Checks
MétodoRutaDescripción
GET/v1/checksLista las chequeos.
POST/v1/checksCrea una chequeo de cualquier tipo.
GET/v1/checks/kindsTipos de chequeo disponibles.
DELETE/v1/checks/{id}Elimina una chequeo.
GET/v1/checks/{id}Detalle de una chequeo (incluye umbrales y estado).
PATCH/v1/checks/{id}Modifica una chequeo (intervalo, umbrales…).
POST/v1/checks/{id}/runFuerza la ejecución inmediata de un chequeo (ignora su planificación).
GET/v1/checks/{id}/statusEstado actual de una chequeo.
Hosts
MétodoRutaDescripción
GET/v1/hostsLista tus monitorizaciones.
POST/v1/hostsCrea una monitorización.
DELETE/v1/hosts/{id}Elimina una monitorización.
GET/v1/hosts/{id}Detalle de una monitorización.
PATCH/v1/hosts/{id}Modifica nombre, IP, descripción o etiquetas de una monitorización.
Events
MétodoRutaDescripción
GET/v1/eventsConsola de eventos.
POST/v1/eventsCrea un evento genérico (integración con otras herramientas).
DELETE/v1/events/{id}Elimina un evento.
POST/v1/events/{id}/ackMarca un evento como validado.
Incidents
MétodoRutaDescripción
GET/v1/incidentsIncidencias (caídas confirmadas), por agente.
GET/v1/incidents/{id}Detalle de una incidencia (árbol de chequeos y evidencia).
PATCH/v1/incidents/{id}Edita título, responsable (owner_id) y criticidad de una incidencia.
POST/v1/incidents/{id}/ackAcusa una incidencia (para MTTA).
POST/v1/incidents/{id}/closeCierra una incidencia abierta (la da por terminada).
POST/v1/incidents/{id}/commentsAñade un comentario a una incidencia (bitácora).
Signals
MétodoRutaDescripción
GET/v1/agents/{id}/signalsSeñales ancladas a un agente.
GET/v1/signalsLista las señales (estado publicado por los emisores).
DELETE/v1/signals/{origin}/{signal_id}Elimina una señal.
GET/v1/signals/{origin}/{signal_id}Detalle de una señal.
PUT/v1/signals/{origin}/{signal_id}Publica una muestra de señal (push).
Metrics
MétodoRutaDescripción
GET/v1/metric-groupsLista los grupos de métricas.
POST/v1/metric-groupsCrea un grupo de métricas.
DELETE/v1/metric-groups/{id}Elimina un grupo de métricas (sus métricas quedan sin grupo).
PATCH/v1/metric-groups/{id}Renombra un grupo de métricas.
GET/v1/metricsLista tus métricas propias.
POST/v1/metricsPublica métricas propias con etiquetas.
GET/v1/metrics/seriesSerie temporal de una métrica.
DELETE/v1/metrics/{name}Elimina una métrica (si se reenvía, se recrea).
PATCH/v1/metrics/{name}Mueve una métrica a un grupo y/o fija su tipo/unidad.
Dashboards
MétodoRutaDescripción
GET/v1/dashboardsLista los dashboards.
POST/v1/dashboardsCrea un dashboard.
DELETE/v1/dashboards/{id}Elimina un dashboard.
GET/v1/dashboards/{id}Detalle de un dashboard.
PATCH/v1/dashboards/{id}Modifica un dashboard.
Logs
MétodoRutaDescripción
GET/v1/logsBusca y filtra los logs de los agentes.
Availability
MétodoRutaDescripción
GET/v1/availabilityDisponibilidad (%) global y por agente.
Auth
MétodoRutaDescripción
POST/v1/auth/agentAlta del plugin (WordPress): email+contraseña → token de AGENTE.
POST/v1/auth/loginLogin por API (público): devuelve un token de usuario.
POST/v1/auth/ssoURL de un solo uso para entrar al panel ya logueado (Bearer).
Event rules
MétodoRutaDescripción
GET/v1/event-rulesLista las reglas de evento (cambio de estado → destino).
POST/v1/event-rulesCrea una regla de evento.
DELETE/v1/event-rules/{id}Borra una regla de evento.
PATCH/v1/event-rules/{id}Modifica una regla de evento.
Report
MétodoRutaDescripción
GET/v1/reportConfiguración del informe por email (frecuencia, hora, zona horaria).
PATCH/v1/reportModifica la configuración del informe.
Users
MétodoRutaDescripción
GET/v1/usersUsuarios del tenant (adicionales al propietario).
POST/v1/usersInvita a un usuario (email + rol). Devuelve el enlace de invitación.
DELETE/v1/users/{id}Elimina un usuario.
PATCH/v1/users/{id}Modifica rol/estado de un usuario.
Node
MétodoRutaDescripción
POST/v1/node/accessDatos de conexión + enlace de login para un emisor externo (secreto de nodo).
GET/v1/node/auditAuditoría de todos los tenants del nodo (secreto de nodo; solo lectura).
POST/v1/node/impersonateEnlace de login de un solo uso para el owner de un tenant (secreto de nodo).
POST/v1/node/provisionAlta de un tenant desde el Cloud Master.
GET/v1/node/selfmetricsAuto-métricas del nodo (secreto de nodo).
POST/v1/node/tenant-deleteBorra COMPLETO un tenant del nodo por client_id (secreto de nodo; irreversible).
GET/v1/node/tenantsResumen de tenants/uso/facturación del nodo (secreto de nodo).
Auditoría
MétodoRutaDescripción
GET/v1/auditAuditoría del tenant (solo lectura).
Tokens
MétodoRutaDescripción
GET/v1/tokensLista los tokens de API del tenant (con agente y alcance).
POST/v1/tokensCrea un token. Con `agent_id` es un **token de agente** (solo datos de ese agente); `scopes` limita qué puede hacer.
DELETE/v1/tokens/{id}Revoca un token.
Remote config
MétodoRutaDescripción
GET/v1/hosts/{id}/remote-configConfiguración remota del endpoint: fichero conf y módulos.
PUT/v1/hosts/{id}/remote-configReemplaza el fichero de configuración remota del endpoint (editor avanzado).
POST/v1/hosts/{id}/remote-config/modulesAñade un módulo a la configuración remota del endpoint.
DELETE/v1/hosts/{id}/remote-config/modules/{name}Borra un módulo de la configuración remota del endpoint.
PATCH/v1/hosts/{id}/remote-config/modules/{name}Modifica un módulo de la configuración remota del endpoint.
Connectors
MétodoRutaDescripción
GET/v1/connectorsCatálogo de conectores (interfaces declarativas).
GET/v1/connectors/tasksTareas de conector del tenant.
POST/v1/connectors/tasksCrea una tarea de conector (config cifrada).
DELETE/v1/connectors/tasks/{tid}Borra una tarea de conector.
POST/v1/connectors/tasks/{tid}/runEjecuta una tarea e ingesta el informe como agentes virtuales + módulos.
GET/v1/connectors/{id}Interfaz (descriptor) de un conector: pasos, campos, tipos, defaults y dependencias.
POST/v1/connectors/{id}/runEjecuta un conector y devuelve el informe (hosts + módulos).
Agent
MétodoRutaDescripción
GET/v1/agent/configMódulos a recolectar e intervalo (requiere token de agente).
PUT/v1/agent/dataPublica un lote de muestras del agente (requiere token de agente).
POST/v1/agent/heartbeatLatido del agente (requiere token de agente).
POST/v1/agent/idGenera una identidad de agente única (agent_ref) para un plugin (público).
PATCH/v1/agent/profileCambia el alias visible del agente (requiere token de agente).
Pollers
MétodoRutaDescripción
GET/v1/pollersPollers de sondeo distribuido registrados.
POST/v1/pollers/heartbeatAlta/latido de un poller de sondeo distribuido.
POST/v1/pollers/jobsSolicita trabajos de sondeo.
POST/v1/pollers/resultsEnvía resultados de sondeo.
DELETE/v1/pollers/{id}Desregistra un poller.
GET/v1/regionsRegiones con pollers vivos.
On-call
MétodoRutaDescripción
GET/v1/oncall/nowQuién está de guardia ahora.
GET/v1/oncall/rotationsRotaciones automáticas de guardia.
POST/v1/oncall/rotationsCrea una rotación automática.
DELETE/v1/oncall/rotations/{id}Elimina una rotación.
GET/v1/oncall/shiftsTurnos de guardia.
POST/v1/oncall/shiftsCrea un turno de guardia.
DELETE/v1/oncall/shifts/{id}Elimina un turno.
GET/v1/teamsEquipos de guardia.
POST/v1/teamsCrea un equipo.
DELETE/v1/teams/{id}Elimina un equipo.
DELETE/v1/teams/{id}/membersQuita un miembro de un equipo.
GET/v1/teams/{id}/membersMiembros de un equipo.
POST/v1/teams/{id}/membersAñade un miembro a un equipo.
Tags
MétodoRutaDescripción
GET/v1/tagsEtiquetas de agente (catálogo del tenant).
POST/v1/tagsCrea o actualiza una etiqueta (nombre + colores).
DELETE/v1/tags/{id}Elimina una etiqueta.
PATCH/v1/tags/{id}Renombra y/o recolorea una etiqueta (propaga el renombrado a agentes y reglas).

Señales (push)

Un chequeo activo lo sondea Pandora Cloud; una señal la publica el propio proceso. Con mode=periodic + interval + keepalive, si el proceso muere y deja de publicar la señal pasa a MUERTA y genera evento/alerta. Con mode=event publicas cuando ocurre algo, sin cadencia. No hace falta IA: vale para cualquier script.

La clave es emisor/señal, en la ruta. Dentro de la muestra, sample.status es la criticidad y sample.lifecycle el ciclo de vida. Cada muestra reemplaza a la anterior: la señal no acumula histórico. El emisor de la ruta ancla la señal: usa el agent_name del endpoint y la señal aparecerá en la solapa Señales de su ficha (si no corresponde a ningún agente, se crea uno nuevo con ese nombre).

1) Latido por cron — «¿sigue vivo este proceso?»

#!/usr/bin/env bash
# /usr/local/bin/backup-nocturno.sh   (cron: */5 * * * *)
set -euo pipefail
TOKEN="pc_TU_TOKEN"; API="http://eu01.cloud.pandorafms.com/api/v1/signals"; EMISOR="$(hostname)"

# ... trabajo real ...

curl -s -X PUT "$API/$EMISOR/backup-nocturno" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"spec":"pandora.signal/v1",
       "signal":{"name":"Backup nocturno","mode":"periodic","interval":300,"keepalive":120},
       "sample":{"status":"ok","lifecycle":"done","summary":"última ejecución correcta"}}'

2) Aviso puntual (evento, sin cadencia)

curl -s -X PUT "$API/backup-runner/copia-bd" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"spec":"pandora.signal/v1",
       "signal":{"name":"Copia de base de datos","mode":"event","shape":"static"},
       "sample":{"seq":311,"ts":"2026-09-26T02:14:09Z","status":"ok",
                 "summary":"Copia completada, 41,2 GB en 14 min"},
       "data":{"size_gb":41.2,"duration_min":14,"target":"s3://backups/db"}}'

3) Tarea larga: ciclo de vida y progreso

TOKEN="pc_TU_TOKEN"; API="http://eu01.cloud.pandorafms.com/api/v1/signals"; S=indexado-catalogo

curl -s -X PUT "$API/opencode/$S" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"signal":{"name":"Indexado de catálogo","mode":"periodic","interval":60,"keepalive":600},
       "sample":{"status":"ok","lifecycle":"running","summary":"1200/2000 productos"},
       "progress":60}'

# Al terminar
curl -s -X PUT "$API/opencode/$S" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"sample":{"status":"ok","lifecycle":"done","summary":"completado"},
       "progress":100}'

4) Consultar el estado

# Una señal
curl -s "http://eu01.cloud.pandorafms.com/api/v1/signals/backup-nocturno/backup-nocturno" -H "Authorization: Bearer $TOKEN"

# Todas las señales del tenant
curl -s "http://eu01.cloud.pandorafms.com/api/v1/signals" -H "Authorization: Bearer $TOKEN"

# Todas las señales de un agente
curl -s "http://eu01.cloud.pandorafms.com/api/v1/agents/13/signals" -H "Authorization: Bearer $TOKEN"

5) Tendencia: publica la métrica y referénciala en el panel

Como la señal no acumula histórico, la tendencia vive en las métricas. Son dos pasos, y el panel dibuja la serie sin que los puntos viajen en la muestra:

# Paso 1: publica el valor que quieres ver evolucionar
curl -s -X POST "http://eu01.cloud.pandorafms.com/api/v1/metrics" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"checkout.latency_p95","value":131,"unit":"ms","tags":{"env":"prod"}}'

# Paso 2: en la señal, el panel apunta a esa métrica (no lleva puntos)
curl -s -X PUT "$API/checkout-api/health" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"signal":{"name":"Salud del servicio","mode":"periodic","interval":60,"keepalive":60},
       "sample":{"status":"ok"},
       "data":{"rps":{"value":412,"unit":"req/s"}},
       "render":{"layout":"grid","panels":[
         {"view":"stat","source":"/rps","title":"Peticiones","w":2},
         {"view":"timeseries","title":"Latencia p95 (24 h)","w":2,
          "options":{"metric":"checkout.latency_p95","tags":{"env":"prod"},"unit":"ms"}}]}}'

También puedes referenciar un chequeo con "options":{"check_id":112120}, o mandar tú los puntos en la propia muestra con {"series":[{"name":"p95","points":[["…",131]]}]} (útil en event, pero engorda la muestra).

Integrar otras herramientas (eventos genéricos)

Cualquier sistema (CI/CD, backups, tareas, scripts, otras herramientas) puede dejar eventos genéricos en la consola, sin que estén ligados a un agente ni a un monitor:

curl -X POST http://eu01.cloud.pandorafms.com/api/v1/events \
  -H "Authorization: Bearer pc_TU_TOKEN" -H "Content-Type: application/json" \
  -d '{"severity":"critical","source":"jenkins","text":"Build #128 falló",
       "details":{"job":"web","build":128,"url":"https://jenkins/job/web/128"}}'

Campos: text (obligatorio), severity (ok, warning, critical, unknown o system; por defecto system), source (origen; por defecto externo) y details (JSON libre). Los eventos aparecen en la consola de eventos.

Un evento puede validarse (POST /v1/events/{id}/ack) o borrarse. La validación no cambia el estado de nada: marca «ya lo he visto». Además, cuando un chequeo se recupera sus eventos pendientes quedan validados solos (ver Avisos).

Campos de una señal

El cuerpo de PUT /v1/signals/{emisor}/{señal} es declarativo: lo que mandas se guarda tal cual (nombre, cadencia, forma) y la muestra reemplaza a la anterior. La API rechaza campos desconocidos: si añades uno que no está en esta tabla, responde 400 bad_json.

CampoTipoQué es
specstringpandora.signal/v1. Informativo, pero conviene mandarlo.
emitterobjectInformativo (id, name, kind). La identidad real es el emisor de la ruta.
signal.namestringNombre visible de la señal.
signal.descriptionstringTexto libre.
signal.tagsarrayEtiquetas (array de cadenas).
signal.agent_idintId interno del agente al que se ancla. Si no existe en tu tenant: 400 unknown_agent. Ver Anclar a un agente.
signal.modeperiodic|eventCon cadencia (latido) o solo cuando ocurre. Por defecto periodic.
signal.intervalint (s)Cada cuánto se espera la muestra.
signal.keepaliveint (s)Margen extra sobre interval antes de declararla muerta.
signal.shapestatic|dynamic|fluidQué se puede comparar con la muestra anterior. Por defecto static.
sample.seqintSecuencia, siempre creciente. Sirve para detectar saltos y muestras repetidas.
sample.tsRFC3339Cuándo ocurrió. Si viene mal formada: 400 invalid_ts. Si se omite, se usa la hora de recepción.
sample.statusok|warning|critical|unknownCriticidad. Alias: sample.severity.
sample.lifecyclequeued|running|waiting|done|error|cancelledCiclo de vida. Si se omite: unknown.
sample.summarystringResumen de una línea. Si lo publicas, se muestra en la ficha; si repite lo que ya dicen los paneles, simplemente no lo mandes. Además forma parte del texto del evento cuando cambia la criticidad (donde sí suele aportar: es lo que se lee en el aviso).
sample.ttlint (s)Caducidad de la muestra.
sample.modulesarrayElementos internos que se guardan como módulos (métrica, estado e histórico): [{"key","name","unit","kind","value","status"}]. La señal cuenta como un módulo y cada elemento declarado también. Aparecen en la tabla de módulos del agente (indentados) y dentro de la señal (solapa Señales). Si se omite, la señal sigue contando como un solo módulo.
dataobjectJSON libre: es lo que pintan los paneles. Se reemplaza entero en cada muestra.
renderobjectPaneles para leer la señal de un vistazo. Ver Vistas del render.
linksarray[{"label","href"}]. Solo http(s): cualquier otro esquema se descarta.
progressnumberProgreso, en 0..1 o 0..100.

La respuesta es la señal guardada. Ojo a un detalle que confunde: status es el ciclo de vida y severity es la criticidad efectiva (la que has enviado, más dead/stale si el sistema la ha declarado muda).

CampoQué es
idId interno de la señal.
origin · signal_idLa clave: emisor y señal (signal_id puede llevar /).
name · description · tagsLo declarado en signal.
agent_idEl agente al que está anclada.
mode · interval · keepalive · shapeCadencia y forma declaradas.
seq · ts · received_atSecuencia, hora de la muestra y hora de recepción en la plataforma.
summaryResumen de la última muestra.
statusCiclo de vida de la última muestra.
severityCriticidad efectiva: ok, warning, critical, unknown, dead o stale.
data · render · links · progressLo que se pintará y lo que se guardó de la muestra.
updated_atÚltima vez que cambió algo de la señal.
Borrar una señal no borra su agente. Con la API, DELETE /v1/signals/{emisor}/{señal} elimina solo la señal. Si quieres limpiar también el agente que creó sola (cuando no le queda ninguna otra señal), hazlo desde la interfaz, que sí elimina «el rastro». Y si borras el agente, se van con él sus señales.

Anclar a un agente

Un agente tiene tres identificadores y conviene no confundirlos:

NombreDóndeQué es
idGET /v1/hostsInterno e inmutable. Es el que se usa como agent_id en las señales.
namenameEl alias: lo que ves en la interfaz y lo que puedes renombrar. Único por tenant.
agent_nameagent_nameLa identidad del agente (el Endpoint Name que ves al editar el agente). En endpoints viene en el XML de Pandora; en los agentes cloud (creados en Pandora Cloud) se fija con el primer nombre que se les da. No se edita.
  • La señal se ancla al agente por su agent_name (Endpoint Name), que es inmutable en endpoints y en agentes cloud; nunca por el alias (name). Por eso puedes renombrar el alias y las señales siguen colgando del mismo agente. Si mandas agent_id, manda el id interno.
  • Si agent_id no existe en tu tenant, la API responde 400 unknown_agent (no crea nada a medias).
  • Si omites agent_id, se usa el emisor de la ruta y se busca un agente con ese agent_name: si existe, la señal cuelga de él y aparece en la solapa Señales de su ficha. En un agente cloud, el agent_name es el nombre con el que lo creaste (el alias que tenga ahora no importa). Si no hay ninguno, se crea un agente nuevo con ese nombre.
  • Un agente no se borra solo porque sus señales desaparezcan: para que no queden agentes huérfanos, bórralas desde la interfaz (que limpia el rastro) o borra el agente si ya no lo quieres.
# Localizar el id interno de un agente
curl -s "http://eu01.cloud.pandorafms.com/api/v1/hosts" -H "Authorization: Bearer $TOKEN" | grep -A3 '"name"'

# Anclar una señal a ese agente
curl -s -X PUT "$API/mi-emisor/mi-tarea" -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"signal":{"name":"Mi tarea","agent_id":18,"mode":"periodic","interval":300,"keepalive":120},
       "sample":{"status":"ok","lifecycle":"running"}}'

Al renombrar el alias de un agente (endpoint o cloud), su agent_name y su id no cambian: el anclaje por nombre se hace contra el agent_name, así que las señales siguen ancladas correctamente.

Coordinar agentes de IA

Si varios agentes (opencode, scripts, cron, CI) ejecutan tareas en distintas máquinas, publicando señales en el mismo tenant obtienes un único tablero con el progreso de todo. Pandora Cloud no ejecuta ni planifica tareas: solo observa el estado que los agentes comparten (observabilidad de solo lectura + estado compartido). El tablero es la solapa Señales de la vista de agentes.

Convenciones

  • emisor: quién y dónde. Va en la ruta y ancla la señal: usa el agent_name del endpoint para que cuelgue de él (cron@srv-01); si no corresponde a ningún agente, se crea uno nuevo con ese nombre.
  • signal_id: estable por tarea dentro del emisor. Usa jerarquía con /: proyecto/area/tarea.
  • agent_id: opcional. El id interno del agente al que anclar la señal; si lo omites, se ancla al endpoint por el agent_name del emisor (si no existe, se crea uno). Ver Anclar a un agente.
  • sample.status (criticidad): ok, warning, critical. sample.lifecycle: running, waiting, done, error…
  • data (JSON libre): project, model, tokens, cost_eur, step, parent…
  • render: paneles para que la tarea se lea de un vistazo (catálogo cerrado, ver Vistas del render).

Patrones de coordinación

  • Un solo tablero: todos los emisores publican en el mismo tenant; el emisor distingue máquina y el signal_id la tarea.
  • Ciclo de vida: running al empezar → actualizaciones → done/error al terminar.
  • Traspaso por estado (sin scheduler): un agente deja waiting con data.next; otro lee GET /v1/signals y toma la tarea poniéndola running.
  • Sub-tareas: prefijo jerárquico en signal_id o data.parent.
  • Detección de caídas: mode=periodic + keepalive ⇒ la señal pasa a dead; cada cambio de criticidad genera un evento.

Helper reutilizable (bash)

export PC_API="http://eu01.cloud.pandorafms.com/api/v1/signals"
export PC_TOKEN="pc_TU_TOKEN"

# Declara la señal (nombre, cadencia y keepalive) la primera vez que publicas:
curl -s -X PUT "$PC_API/opencode/seo/site-a/informe" -H "Authorization: Bearer $PC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"spec":"pandora.signal/v1",
       "signal":{"name":"Informe SEO site-a","mode":"periodic","interval":60,"keepalive":600},
       "sample":{"status":"ok","lifecycle":"running","summary":"analizando enlaces"},
       "data":{"project":"seo","model":"deepseek-flash","tokens":184320}}'

# Y a partir de ahí, solo la muestra: emisor, señal, criticidad, ciclo y resumen.
pc_sig() { # pc_sig <emisor> <señal> <criticidad> <ciclo> <resumen>
  local emisor="$1" sig="$2" sev="$3" life="$4" sum="$5"
  curl -s -X PUT "$PC_API/$emisor/$sig" -H "Authorization: Bearer $PC_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"sample\":{\"status\":\"$sev\",\"lifecycle\":\"$life\",\"summary\":\"$sum\"}}" >/dev/null
}

pc_sig opencode "seo/site-a/informe" ok running "7/11 secciones"
#   ... trabajo ...
pc_sig opencode "seo/site-a/informe" ok done "informe listo"

Helper reutilizable (Python)

import json, socket, urllib.request

class Signal:
    def __init__(self, token, emisor=None, api="http://eu01.cloud.pandorafms.com/api/v1/signals"):
        self.token = token
        self.emisor = emisor or f"opencode@{socket.gethostname()}"
        self.api = api

    def declarar(self, sig, name, mode="periodic", interval=300, keepalive=120,
                 shape="static", agent_id=None):
        s = {"name": name, "mode": mode, "shape": shape}
        if mode == "periodic":
            s.update(interval=interval, keepalive=keepalive)
        if agent_id:
            s["agent_id"] = agent_id
        return self._put(sig, {"spec": "pandora.signal/v1", "signal": s,
                               "sample": {"status": "ok", "lifecycle": "running"}})

    def muestra(self, sig, status="ok", lifecycle="running", summary="",
                data=None, render=None, progress=None, seq=None):
        body = {"sample": {"status": status, "lifecycle": lifecycle, "summary": summary},
                "data": data or {}}
        if seq is not None:   body["sample"]["seq"] = seq
        if render is not None: body["render"] = render
        if progress is not None: body["progress"] = progress
        return self._put(sig, body)

    def _put(self, sig, body):
        req = urllib.request.Request(f"{self.api}/{self.emisor}/{sig}",
            data=json.dumps(body).encode(), method="PUT",
            headers={"Authorization": f"Bearer {self.token}",
                     "Content-Type": "application/json"})
        return json.loads(urllib.request.urlopen(req).read())

pc = Signal("pc_TU_TOKEN")
pc.declarar("campana/site-a/borrador", "Borrador SEO site-a", interval=60, keepalive=600)
pc.muestra("campana/site-a/borrador", "ok", "running", "redactando",
           data={"project": "seo", "model": "deepseek-flash", "tokens": 184320},
           progress=65)

Señal completa (tarea de IA)

PUT http://eu01.cloud.pandorafms.com/api/v1/signals/opencode/seo/site-a/informe
{
  "spec": "pandora.signal/v1",
  "emitter": {"id": "opencode@mac-slerena", "name": "opencode", "kind": "ai_agent"},
  "signal": {
    "name": "Informe SEO site-a", "agent_id": 13,
    "mode": "periodic", "interval": 60, "keepalive": 600, "shape": "static"
  },
  "sample": {"seq": 42, "status": "ok", "lifecycle": "running",
             "summary": "Generando secciones (7/11)"},
  "data": {
    "project": "seo", "model": "deepseek-flash", "tokens": 184320,
    "secciones": {"hechas": 7, "total": 11}
  },
  "render": {"layout": "grid", "panels": [
    {"view": "stat", "source": "/tokens", "title": "Tokens", "w": 1},
    {"view": "kv_table", "source": "", "w": 3},
    {"view": "timeseries", "title": "Coste acumulado (24 h)", "w": 4,
     "options": {"metric": "seo.cost_eur", "unit": "EUR"}}
  ]},
  "links": [{"label": "Borrador", "href": "https://ejemplo.com/informe.html"}]
}

Integración con opencode: haz que el agente llame a pc_sig (o a la clase Signal) al empezar y terminar cada tarea, o envuélvelo en tu runner. Cada emisor escribe solo sus señales; la lectura es compartida.

Métricas propias

Publica series propias con etiquetas libres: numéricas (CPU, cola, latencia…) o de estado (OK / NO OK). Son items sueltos, más simples que las señales, y sí acumulan histórico: son la vía para las tendencias.

TOKEN="pc_TU_TOKEN"; API="http://eu01.cloud.pandorafms.com/api/v1"

# Numérica (con etiquetas y unidad)
curl -s -X POST "$API/metrics" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"cpu.load","value":0.42,"unit":"%","tags":{"host":"srv1"}}'

# Estado (OK / aviso / NO OK)
curl -s -X POST "$API/metrics" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"backup-nocturno","kind":"status","status":"ok","tags":{"host":"srv1"}}'

# Lote (hasta 1000 puntos por petición)
curl -s -X POST "$API/metrics" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '[{"name":"queue.jobs","value":3},{"name":"http.latency_ms","value":184}]'

# Consultar una serie
curl -s "$API/metrics/series?name=cpu.load&range=24h" -H "Authorization: Bearer $TOKEN"
CampoQué es
nameObligatorio. Se recorta a 150 caracteres.
valueNúmero. En las de estado se normaliza (ver abajo).
tsRFC3339. Si se omite, la hora de recepción.
tagsMapa libre: {"host":"srv1","env":"prod"}. Distinguen series del mismo nombre.
unitUnidad para mostrarla (%, ms, MB…).
kindnumeric o status. Si no lo mandas y trae status, se infiere status.
statusSolo para kind=status: ok/up → 1, warn/degraded → 0,5, cualquier otra cosa → 0.

La respuesta de GET /v1/metrics da, por métrica, name, points, last_ts y last_value. GET /v1/metrics/series acepta name (obligatorio), tags, range (2h, 24h, 7d, 30d, 180d; por defecto 24h) y since (RFC3339). Devuelve points como [{"t","v","s"}], ya agregados (la agregación cambia con el rango: de 1 minuto a 12 horas por punto).

Puedes fijar el tipo y la unidad y mover una métrica a un grupo con PATCH /v1/metrics/{name}; los grupos se gestionan en /v1/metric-groups. Las métricas se ven en la solapa Métricas de la vista de agentes.

Los umbrales de una métrica se definen hoy en la interfaz (engranaje de la métrica), no por API; los de un chequeo o un módulo sí se pueden fijar por API (PATCH /v1/checks/{id}). Ver Avisos y repetición.

Avisos y repetición

Cuando algo cambia de estado, Pandora Cloud registra un evento y, si procede, envía un aviso por los canales que tengas configurados (email, Discord, Telegram, SMS, llamada de voz, Slack, Teams o webhook) en Configuración. El SMS usa la pasarela de la plataforma y consume el cupo mensual del plan (visible en Cuenta → «Licencia y uso» y en GET /v1/me); la llamada de voz lee el aviso con TTS (útil como escalado). Hay tres fuentes de aviso:

FuenteSe dispara cuando…Se configura
Chequeo (activo) y móduloCruza un umbral (aviso o crítico), o se recupera.API: PATCH /v1/checks/{id} · también en la interfaz.
Métrica propiaCruza su umbral (manual o auto) y al volver a rango.Interfaz (engranaje de la métrica).
SeñalReconecta tras X tiempo parada, o su data cumple una condición.Interfaz (engranaje de la señal).

Umbrales de un chequeo o módulo

Vale para módulos de agente y para chequeos de sondeo (conectividad, web, puerto, SSL/dominio…). threshold_mode: manual (los valores que indiques), auto (del histórico: aviso p90 y crítico p97; en caducidad, invertido) o none. En módulos de agente hay además xml (los que trae el agente), que no aplica a los sondeos. La banda es el rango «malo»: min_warning/max_warning (y el crítico) acotan ese rango; p. ej. RTT → aviso si ≥150 (min_warning=150), caducidad → aviso si quedan ≤30 días (max_warning=30).

curl -X PATCH http://eu01.cloud.pandorafms.com/api/v1/checks/112120 -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"threshold_mode":"manual","min_warning":80,"max_warning":90,
       "min_critical":95,"max_critical":100}'

Umbrales de una métrica

Igual, pero en el engranaje de la métrica: sin umbrales, manual (mín/máx de aviso y crítico) o automático (percentiles 90/97 del histórico de 7 días; necesita al menos 20 medidas).

Avisos de una señal

Dos condiciones opcionales e independientes, en el engranaje de la señal:

  • Reconexión: avisa cuando la señal vuelve a reportar después de haber estado ese tiempo sin hacerlo. La primera vez solo fija la referencia, no avisa.
  • Condición sobre un token de data: avisa cuando el valor de ese campo cumple igual a, distinto de, menor que o mayor que. Es la forma de avisar de un valor concreto («fallos > 0»).

Repetición: cada cuánto se vuelve a avisar

Las tres fuentes comparten la misma regla (alert_repeat_s), que es la parte que más se malinterpreta:

ValorSignificado
NULL (vacío)Solo la primera vez. No se repite mientras dure la incidencia.
0Cada vez que se evalúa y la condición sigue cumpliéndose.
N > 0Como mucho una vez cada N segundos.
Sin tocar (por defecto)86 400 (24 horas).

En los chequeos, la repetición afecta tanto al cruce de umbral como al recordatorio de incidencias abiertas (un chequeo caído sigue avisando cada N mientras no se recupere).

Y al recuperarse…

Cuando un chequeo (o su keepalive) vuelve a estar bien, sus eventos pendientes quedan validados automáticamente: no hay que limpiarlos a mano. El evento de recuperación sí se registra, para que quede el rastro de la caída y la vuelta.

Modo silencioso

El modo silencioso decide qué puede generar un chequeo o un agente entero, sin dejar de monitorizarlo: sigue midiendo y pintando estado, pero no genera ruido.

ModoEventosIncidenciasAvisos
all — aviso completo (por defecto)sísísí
none — silencio totalnonono
alerts — solo alertasnonosí
events — solo eventossínono
incidents — solo incidenciasnosíno
  • Se puede poner por agente (se aplica a todos sus chequeos) y por chequeo.
  • El del chequeo manda: si no es all, se usa el suyo; si es all, hereda el del agente.
  • En la interfaz, un punto junto a la burbuja de estado indica que ese chequeo o agente tiene un modo silencioso distinto del normal.
Hoy el modo silencioso se cambia desde la interfaz: no hay campo en la API (PATCH /v1/hosts/{id} y PATCH /v1/checks/{id} no lo aceptan). Si lo necesitas para automatizar, dímelo y se añade.

Vistas del render

Campo render.panels[]. Cada panel elige una vista del catálogo y apunta a una parte de data con JSON Pointer (source); o referencia una serie ya almacenada (options.metric / options.check_id), que es la vía recomendada para tendencias. Si no envías render, data se muestra como tabla. Una vista desconocida o una ruta inválida se pintan como tabla con un aviso: nunca rompen la página.

VistaEspera en sourceOpciones
kv_tableObjeto plano {clave: valor}order. Vista por defecto.
table{"columns":[…],"rows":[[…]]} o array de objetosstatus_column
status{"nombre": true|false|"ok"|"warning"|"critical"}—
log[{"ts","level","text"}]max_lines
textTexto en markdown restringido (negritas, cursivas, saltos)—
statNúmero, o {"value","unit","delta"}unit, thresholds
gauge{"value","min","max"}unit, thresholds
timeseries{"series":[{"name","points":[[ts,valor]]}]} — o nada si usas options.metric/check_idmetric, tags, check_id, range, unit
linksArray [{"label","href"}]—

w: ancho relativo en rejilla de 4 columnas (con layout:"grid"; con layout:"stack" los paneles van uno debajo de otro). El bloque links[] de la señal es aparte y solo admite http(s). El progreso (progress) se pinta solo con la vista gauge o stat, no es una vista.

Degradación: si el emisor manda algo que no encaja (una vista que no existe, un source que no apunta a nada, un tipo inesperado), el panel se pinta como tabla con un aviso y el resto de la señal sigue funcionando. Es a propósito: una señal mal formada no puede romper la página.

Generadores de señales

Un emisor es un proceso externo que publica su estado. Para que cualquiera lo encuentre y lo mantenga, hay un estándar: todo emisor vive en deploy/<emisor>/ del repositorio del producto que emite, con el publicador, sus unidades de arranque, un install.sh idempotente y un README.md. La configuración y el token no van al repositorio: viven en ~/.config/pandora-cloud/<emisor>.env (0600).

La cadencia se declara dos veces, a propósito: en el sistema (systemd --user con .timer, o LaunchAgent en macOS) y en la señal (mode=periodic + interval + keepalive). Si solo estuviera el timer, un emisor muerto o una máquina apagada serían invisibles.

  • Busca un emisor existente antes de crear uno. Duplicarlos es la causa número uno de señales fantasma.
  • No hay histórico: para tendencia, publica la métrica y referénciala en el panel.
  • Criticidad (sample.status) y ciclo de vida (sample.lifecycle) son dimensiones distintas.
  • La API rechaza campos desconocidos: el cuerpo debe ajustarse al esquema, sin campos de más (ver Campos de una señal).
  • seq siempre creciente; keepalive si quieres detección de caída.
  • Una sola máquina, un solo emisor: incluye el nombre del equipo en el emisor (opencode@mac-slerena) para que dos máquinas no se pisen la misma señal.

El estándar completo está en el repositorio (docs/guia-emisores-senales.md) y como skill que los agentes cargan a demanda: Skills del proyecto. Implementación de referencia: deploy/aw-usage-cloud/.

Agentes Pandora (endpoints)

Además de los chequeos que sondea la plataforma, Pandora Cloud puede recibir datos de los agentes Pandora (los endpoints clásicos). El agente envía su XML con lo que vigila y la plataforma lo traduce a sus propias entidades:

  • Agente → monitorización con origin: "agent". Se llama igual que en el XML (agent_name) y puedes renombrarlo con un alias sin perder el vínculo.
  • Módulo → chequeo de tipo agent, pasivo: no lo sondea el planificador, el dato llega del endpoint.
  • Si un agente deja de enviar, el keepalive lo detecta y genera evento, incidencia y aviso, igual que un chequeo activo.
  • Los cambios de estado de un módulo generan evento + incidencia + aviso desde la propia ingesta. El aviso inicial lo manda la pasada periódica (marca notified_at).
Módulos incrementales. Algunos módulos (generic_data_inc) envían un contador acumulado (bytes, peticiones, errores desde el arranque), no un valor instantáneo. Para leerlos hay que usar la variación entre muestras: dibujar el valor crudo da una rampa que siempre sube y no significa nada. La interfaz ya lo hace; si consumes esos datos por API, tenlo en cuenta.

La ingesta (cmd/pandora-ingest) lee los XML de ~/tentacle/data y los archiva en processed/ o failed/. La configuración del agente vive en /etc/pandora/pandora_agent.conf, que en la máquina del agente solo puede leer root: si un emisor quiere usar el nombre del agente y no puede leerlo, usa otra vía (variable de entorno o el nombre del equipo) — es una trampa conocida.

Logs

Los logs son las líneas que envían los agentes Pandora (no los chequeos). Se consultan con:

curl -s "http://eu01.cloud.pandorafms.com/api/v1/logs?agent=srv-01&q=timeout&since=2026-09-26T00:00:00Z&limit=100" \
  -H "Authorization: Bearer $TOKEN"
ParámetroQué es
agentFiltra por agente.
sourceFiltra por módulo o fuente.
qSubcadena en el mensaje.
since · untilRFC3339. Por defecto, las últimas 24 horas.
limit · offsetPaginación.

Respuesta: total, limit, offset y logs. La retención y el volumen diario dependen de tu plan (ver Planes y cuotas): al agotar el cupo diario se dejan de guardar líneas hasta el día siguiente, y pasado el plazo se purgan.

Límites e intervalos

LímiteValor
Intervalo mínimo de un chequeo300 s (5 minutos). Si pides menos, se ajusta al mínimo sin avisar.
Certificado SSL y caducidad de dominio43 200 s (12 horas) de mínimo: no tiene sentido mirarlos más a menudo.
Señal: interval y keepaliveEn segundos, sin mínimo impuesto (los pone tu emisor).
Emisor y señal (origin, signal_id)200 caracteres cada uno.
Nombre de métrica150 caracteres (se recorta).
Puntos por petición de métricas1000 (POST /v1/metrics admite un objeto o un array).
Tamaño del cuerpo4 MB.
Retención de datos de monitorizaciónFijada por el plan (90 días por defecto).
El catálogo de tipos de chequeo y sus parámetros se consulta en vivo en GET /v1/me (campo check_kinds) o GET /v1/checks/kinds: https/http (contains, not_contains, expect_status, redirect_to), icmp, tcp (port), ssl/domain (warn_days, crit_days), dns (expect_ip), api (method, headers, body, expect_status, contains, not_contains, json_path, json_expect), correo mx/spf/dmarc, rbl (lists), banner (port, expect, send, tls), headers (require) y sitemap (file, contains).

Planes y cuotas

El plan del tenant fija los límites: agentes, chequeos, el cupo de logs y los envíos de SMS al mes. Tus números exactos, en GET /v1/me (quotas y usage).

PlanAgentesChequeosUsuarios adic.SMS/mesLogs/díaRetención de logs
Gratuito (free)201003102 MB7 días
Professional505005505 MB10 días
Enterprise10010001010015 MB15 días

Al alcanzar un límite, la API responde 403 quota (y la interfaz avisa antes de dejarte crear nada). El cupo de logs es diario: si se agota, se dejan de guardar líneas hasta el día siguiente; pasado el plazo de retención, se purgan.

Errores

Formato uniforme: {"error":{"code":"...","message":"..."}}.

HTTPcodeMotivo
400bad_jsonCuerpo ilegible, o con campos que no existen en el esquema.
400invalidFalta un campo obligatorio o el valor no vale.
400invalid_tssample.ts no es ISO 8601 (RFC3339).
400invalid_checkChequeo no válido (tipo desconocido, destino no permitido…).
400unknown_agentEl agent_id de la señal no existe en tu tenant.
401unauthorizedFalta el token o no es válido.
403quotaSe ha alcanzado una cuota del plan.
404not_foundEl recurso no existe en tu tenant.
405methodMétodo no permitido.
409conflictYa existe (p. ej. un grupo de métricas con ese nombre).
500internalError del servidor.

Los rangos privados están prohibidos como destino de un chequeo: si apuntas a una IP interna, la API lo rechaza. Los chequeos se ejecutan desde los servidores de Pandora Cloud, nunca desde tu red.

Versionado

API v1, versionada en la ruta (/api/v1/…). El proyecto es API-first: toda funcionalidad nueva se expone en la API y se documenta aquí; un test de contrato verifica que rutas y especificación están sincronizadas.

Especificación completa: openapi.json (OpenAPI 3.1).