Referencia de la API REST

Endpoints, autenticación JWT, ejemplos con curl y patrones de error de la API de HeroCtl.

API·12 min de lectura·última revisión 2026-04-26

La API de HeroCtl es el canal único entre tú, el CLI y la interfaz web. Todo lo que el panel muestra pasa por aquí. Todo lo que heroctl hace en la línea de comandos también.

La API es REST. JSON en la entrada, JSON en la salida. Sin GraphQL. Sin gRPC público.

Endpoint base

https://manage.<seu-dominio>/v1/

En producción estándar: https://manage.heroctl.com/v1/.

Todas las rutas viven bajo /v1/. Cuando llegue v2, v1 sigue respondiendo por al menos 12 meses.

Autenticación

La API usa JWT. Obtienes un token vía login y lo envías en cada petición:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Sin header, sin respuesta. El servidor responde 401.

Login

curl -X POST https://manage.heroctl.com/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123"}'

Respuesta:

{
  "token": "eyJhbGciOi...",
  "expires_at": "2026-04-27T15:00:00Z",
  "refresh_token": "rt_8f3a..."
}

El token estándar dura 24 horas.

También puedes autenticarte con un ACL token (generado por la interfaz o por el CLI):

curl -X POST https://manage.heroctl.com/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"acl_token":"ht_a1b2c3d4..."}'

Refresh

Antes de que expire el token, cámbialo por uno nuevo:

curl -X POST https://manage.heroctl.com/v1/auth/refresh \
  -H "Authorization: Bearer $TOKEN"

Endpoints principales

Jobs

Un job es la definición declarativa de lo que debe correr. El cluster se encarga del resto.

MétodoRutaQué hace
GET/v1/jobsLista todos los jobs
GET/v1/jobs/:nameDetalle de un job
POST/v1/jobsEnvía o actualiza un job
DELETE/v1/jobs/:nameElimina el job y sus instancias

Listar jobs:

curl -s https://manage.heroctl.com/v1/jobs \
  -H "Authorization: Bearer $TOKEN" | jq '.[] | .name'

Enviar un job:

curl -X POST https://manage.heroctl.com/v1/jobs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @meu-job.json

Allocations

Cada réplica de un job se vuelve una allocation. Es la unidad de ejecución real.

MétodoRutaQué hace
GET/v1/allocationsLista allocations
GET/v1/allocations/:idDetalle
POST/v1/allocations/:id/stopDetiene una allocation
curl -s "https://manage.heroctl.com/v1/allocations?job=heroctl-site" \
  -H "Authorization: Bearer $TOKEN" | jq '.[] | {id, node, status}'

Nodes

Los servidores que corren workloads.

MétodoRutaQué hace
GET/v1/nodesLista nodos
GET/v1/nodes/:idDetalle (cpu, ram, disk, status)
POST/v1/nodes/:id/drainDrena un nodo (mueve workloads fuera)

Drenar un nodo antes de mantenimiento:

curl -X POST https://manage.heroctl.com/v1/nodes/server-2/drain \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"deadline_seconds": 300}'

Atención: drain remueve todas las allocations del nodo. Garantiza capacidad en los demás antes.

Cluster

MétodoRutaQué hace
GET/v1/cluster/statusSalud general, nodo coordinador, número de miembros
GET/v1/cluster/peersLista de pares del plano de control
POST/v1/raft/transfer-leadershipTransfiere coordinación (admin)
curl -s https://manage.heroctl.com/v1/cluster/status \
  -H "Authorization: Bearer $TOKEN" | jq

Secretos

Valores sensibles. Almacenados cifrados en reposo.

MétodoRutaQué hace
GET/v1/secretsLista nombres (nunca valores)
POST/v1/secretsCrea o actualiza
GET/v1/secrets/:nameLee un valor (requiere ACL específica)
DELETE/v1/secrets/:nameBorra

Crear un secreto:

curl -X POST https://manage.heroctl.com/v1/secrets \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"db_password","value":"s3nh@-forte"}'

Métricas

MétodoRutaQué hace
GET/v1/metricsSnapshot actual (CPU, mem, allocs, ingress)
GET/v1/metrics/queryQuery histórica con ventana de tiempo
curl -s "https://manage.heroctl.com/v1/metrics/query?metric=cpu&job=heroctl-site&from=-1h" \
  -H "Authorization: Bearer $TOKEN" | jq

Logs

Los logs viven por allocation.

MétodoRutaQué hace
GET/v1/logs/:allocÚltimas N líneas
GET/v1/logs?stream=trueStreaming vía SSE

Streaming en vivo:

curl -N "https://manage.heroctl.com/v1/logs?job=heroctl-site&stream=true" \
  -H "Authorization: Bearer $TOKEN"

La salida viene en formato text/event-stream:

event: log
data: {"alloc":"a1b2","line":"server started"}

Health

Endpoints sin autenticación. Para uso de monitoreo externo.

MétodoRutaQué hace
GET/v1/health/readyListo para recibir tráfico
GET/v1/health/liveProceso vivo
curl -s https://manage.heroctl.com/v1/health/ready
# {"status":"ok"}

Ingress

Dominios servidos por el cluster.

MétodoRutaQué hace
GET/v1/ingressTodos los dominios activos
GET/v1/ingress/:hostDetalle de un dominio (cert, rutas, job objetivo)
curl -s https://manage.heroctl.com/v1/ingress/heroctl.com \
  -H "Authorization: Bearer $TOKEN" | jq

Long polling

Varios endpoints soportan espera bloqueante. En vez de hacer poll cada segundo, pasas un índice y el tiempo máximo de espera. La respuesta vuelve cuando algo cambia — o cuando el tiempo se acaba.

curl -s "https://manage.heroctl.com/v1/jobs?wait=5m&index=42" \
  -H "Authorization: Bearer $TOKEN"
  • index=N — índice de la última versión que viste.
  • wait=5m — tiempo máximo de espera (máximo 10m).

Si nada cambia en 5 minutos, la respuesta vuelve con el mismo índice. Se reusa el índice en la próxima llamada.

Esto reduce tráfico y latencia drásticamente en paneles en vivo.

Rate limiting

Cada token tiene un límite de 1000 peticiones por minuto. Por encima de eso el servidor responde:

HTTP/1.1 429 Too Many Requests
Retry-After: 12

El header Retry-After indica en segundos cuándo puedes intentar de nuevo.

Los tokens admin tienen límite separado y más generoso. Para automatización pesada, pide un token de servicio dedicado.

Códigos de error

CódigoSignificado
200OK
201Creado
400Petición inválida (JSON malformado, campo faltante)
401Token ausente, expirado o inválido
403Token válido, pero sin permiso para la ruta
404Recurso no existe
409Conflicto (ej.: crear job con nombre existente)
429Rate limit alcanzado
500Error interno
503Cluster temporalmente sin coordinación

Los errores vienen con cuerpo estandarizado:

{
  "error": "job_not_found",
  "message": "job 'foo' não existe",
  "request_id": "req_a1b2c3"
}

Siempre incluye el request_id cuando abras un ticket de soporte.

Webhooks (Plan Business)

Registras una URL y el cluster envía POSTs en eventos relevantes.

curl -X POST https://manage.heroctl.com/v1/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "url": "https://api.minha-empresa.com/heroctl-events",
    "events": ["job.deployed", "alloc.failed", "node.down"],
    "secret": "whk_a1b2c3"
  }'

Eventos disponibles:

  • job.submitted — nuevo job enviado
  • job.deployed — todas las réplicas saludables
  • job.failed — deploy falló e hizo rollback
  • alloc.failed — una instancia cayó
  • node.down — un servidor salió del cluster
  • cert.renewed — certificado TLS renovado
  • secret.changed — valor de secreto actualizado

Cada POST trae un header X-HeroCtl-Signature con HMAC-SHA256 del cuerpo, usando el secret que registraste. Valida antes de procesar.

Próximos pasos

#api#rest#jwt#curl#webhooks