REST API reference

Endpoints, JWT authentication, curl examples, and error patterns of the HeroCtl API.

API·12 min read·last reviewed 2026-04-26

The HeroCtl API is the single channel between you, the CLI, and the web interface. Everything the panel shows passes through here. Everything heroctl does on the command line too.

The API is REST. JSON in, JSON out. No GraphQL. No public gRPC.

Base endpoint

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

In standard production: https://manage.heroctl.com/v1/.

All routes live under /v1/. When v2 arrives, v1 keeps responding for at least 12 months.

Authentication

The API uses JWT. You obtain a token via login and send it on every request:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

No header, no response. The server replies 401.

Login

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

Response:

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

The default token lasts 24 hours.

You can also authenticate with an ACL token (generated through the interface or the CLI):

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

Refresh

Before the token expires, swap it for a new one:

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

Main endpoints

Jobs

A job is the declarative definition of what should run. The cluster takes care of the rest.

MethodRouteWhat it does
GET/v1/jobsLists all jobs
GET/v1/jobs/:nameDetail of a job
POST/v1/jobsSubmits or updates a job
DELETE/v1/jobs/:nameRemoves the job and its instances

List jobs:

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

Submit a job:

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

Allocations

Each replica of a job becomes an allocation. It's the actual unit of execution.

MethodRouteWhat it does
GET/v1/allocationsLists allocations
GET/v1/allocations/:idDetail
POST/v1/allocations/:id/stopStops an allocation
curl -s "https://manage.heroctl.com/v1/allocations?job=heroctl-site" \
  -H "Authorization: Bearer $TOKEN" | jq '.[] | {id, node, status}'

Nodes

The servers that run workloads.

MethodRouteWhat it does
GET/v1/nodesLists nodes
GET/v1/nodes/:idDetail (cpu, ram, disk, status)
POST/v1/nodes/:id/drainDrains a node (moves workloads off)

Drain a node before maintenance:

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

Warning: drain removes all allocations from the node. Make sure capacity exists on the others first.

Cluster

MethodRouteWhat it does
GET/v1/cluster/statusOverall health, coordinator node, member count
GET/v1/cluster/peersList of control plane peers
POST/v1/raft/transfer-leadershipTransfers coordination (admin)
curl -s https://manage.heroctl.com/v1/cluster/status \
  -H "Authorization: Bearer $TOKEN" | jq

Secrets

Sensitive values. Stored encrypted at rest.

MethodRouteWhat it does
GET/v1/secretsLists names (never values)
POST/v1/secretsCreates or updates
GET/v1/secrets/:nameReads a value (requires specific ACL)
DELETE/v1/secrets/:nameDeletes

Create a secret:

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"}'

Metrics

MethodRouteWhat it does
GET/v1/metricsCurrent snapshot (CPU, mem, allocs, ingress)
GET/v1/metrics/queryHistorical query with time window
curl -s "https://manage.heroctl.com/v1/metrics/query?metric=cpu&job=heroctl-site&from=-1h" \
  -H "Authorization: Bearer $TOKEN" | jq

Logs

Logs live per allocation.

MethodRouteWhat it does
GET/v1/logs/:allocLast N lines
GET/v1/logs?stream=trueStreaming via SSE

Live streaming:

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

The output comes in text/event-stream format:

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

Health

Endpoints without authentication. For external monitoring use.

MethodRouteWhat it does
GET/v1/health/readyReady to accept traffic
GET/v1/health/liveProcess alive
curl -s https://manage.heroctl.com/v1/health/ready
# {"status":"ok"}

Ingress

Domains served by the cluster.

MethodRouteWhat it does
GET/v1/ingressAll active domains
GET/v1/ingress/:hostDetail of a domain (cert, routes, target job)
curl -s https://manage.heroctl.com/v1/ingress/heroctl.com \
  -H "Authorization: Bearer $TOKEN" | jq

Long polling

Several endpoints support blocking waits. Instead of polling every second, you pass an index and a maximum wait time. The response returns when something changes — or when the time runs out.

curl -s "https://manage.heroctl.com/v1/jobs?wait=5m&index=42" \
  -H "Authorization: Bearer $TOKEN"
  • index=N — index of the last version you saw.
  • wait=5m — max wait time (max 10m).

If nothing changes in 5 minutes, the response comes back with the same index. Reuse the index in the next call.

This dramatically reduces traffic and latency on live panels.

Rate limiting

Each token has a limit of 1000 requests per minute. Above that the server replies:

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

The Retry-After header indicates in seconds when you can try again.

Admin tokens have a separate, more generous limit. For heavy automation, request a dedicated service token.

Error codes

Status codeMeaning
200OK
201Created
400Invalid request (malformed JSON, missing field)
401Token missing, expired, or invalid
403Token valid, but no permission for the route
404Resource does not exist
409Conflict (e.g., creating a job with an existing name)
429Rate limit hit
500Internal error
503Cluster temporarily without coordination

Errors come with a standardized body:

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

Always include the request_id when you open a support ticket.

Webhooks (Business plan)

You register a URL and the cluster sends POSTs on relevant events.

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"
  }'

Available events:

  • job.submitted — new job submitted
  • job.deployed — all replicas healthy
  • job.failed — deploy failed and rolled back
  • alloc.failed — an instance went down
  • node.down — a server left the cluster
  • cert.renewed — TLS certificate renewed
  • secret.changed — secret value updated

Each POST carries an X-HeroCtl-Signature header with HMAC-SHA256 of the body, using the secret you registered. Validate before processing.

Next steps

#api#rest#jwt#curl#webhooks