The REST API

A task-oriented tour of the runtime's built-in HTTP endpoints — metadata, topology, state and progress, health, control, license, metrics, and debug.

The :runtime module starts a small HTTP server alongside your topology. It serves operational endpoints — metadata, topology views, live state and progress, health probes, control actions, license state, Prometheus metrics, and freeze diagnostics. Everything below is what an operator reaches for from a shell, a dashboard, or a Kubernetes probe.

Enabling the server

The HTTP server is configured under runtime.http. It's enabled by default; metrics live under runtime.metrics:

runtime:
  http:
    enabled: true
    port: 8080          # default
    host: 0.0.0.0       # default — all interfaces
    debug:
      enabled: true     # default — /debug/* endpoints
  metrics:
    enabled: true

A quick liveness check from the shell:

curl -s localhost:8080/health/ready
Several endpoints expose internals or customer-identifying data — /license (license ID, customer name, machine counts), /config, /info, the /topology/* views, and /debug/*. Expose only /health/live and /health/ready through internet-facing ingress; keep the rest on the in-cluster Service. See Kubernetes and Probes.

All read endpoints are GET. Calling one with the wrong method returns 405. Before the engine has finished starting, endpoints that depend on it return 503 with a short JSON error.

Metadata

Use these to confirm what's deployed and how it's configured.

EndpointMethodPurpose
/infoGETApplication ID, JVM and Kafka info, uptime, current state, and the list of registered endpoints.
/configGETThe merged effective configuration, with secrets masked.

/info is the fastest way to see what's running and which endpoints this build exposes — the endpoints array is generated from the actual handler registration:

curl -s localhost:8080/info

/config content-negotiates: it returns YAML by default (more readable), or JSON if you ask for it. Passwords, secrets, and tokens are masked in the output.

# YAML (default)
curl -s localhost:8080/config

# JSON
curl -s -H 'Accept: application/json' localhost:8080/config

Topology

Three views of the same topology, for different audiences.

EndpointMethodPurpose
/topologyGETStoatFlow-native view with rich metadata (scheduled sources, store names, sub-topology structure).
/topology/ksGETKafka Streams-compatible view, matching Topology#describe() output.
/topology/compiledGETThe compiled, runtime-internal representation produced by the topology compiler.

/topology and /topology/ks return a human-readable text description by default, or JSON when you request it:

# Text (default)
curl -s localhost:8080/topology

# JSON
curl -s -H 'Accept: application/json' localhost:8080/topology

# Kafka Streams-compatible description
curl -s localhost:8080/topology/ks

/topology/compiled reflects how the engine actually compiled and laid out your topology, which can differ from the logical DSL view (for example where key-changing operations introduce sub-topology boundaries). It's primarily a diagnostic view; it returns 503 until the application has started.

curl -s -H 'Accept: application/json' localhost:8080/topology/compiled

State and progress

These show whether the application is making progress and where it's at — lifecycle state, consumer assignment, offset lag, and event-time watermarks.

EndpointMethodPurpose
/stateGETCurrent lifecycle state, when it was entered, and the recent state-transition history.
/consumerGETConsumer group metadata, source subscription, last commit time, and per-partition buffer fill + pause state.
/offsetsGETPer-partition committed offsets and lag for source topics, plus committed changelog offsets per state store.
/watermarksGETGlobal and per-partition event-time watermarks, idle flags, and last event times.

/state is the lifecycle picture — is the app RUNNING, DRAINING, PAUSED, restoring, shutting down?

curl -s localhost:8080/state

/offsets answers "are we falling behind?" — it reports per-partition lag and a totalLag summary, derived from locally cached values (no Kafka RPCs on the request path):

curl -s localhost:8080/offsets

/consumer adds the consumer-group angle (member ID, generation, subscription) and shows per-partition buffer utilisation, so you can see whether any partition is paused under backpressure. /watermarks exposes event-time progress — useful when windowed or timer-driven logic seems to be waiting.

curl -s localhost:8080/consumer
curl -s localhost:8080/watermarks

See Event time and watermarks for how watermarks advance, and Observability for turning these into dashboards.

Health probes

Kubernetes-style liveness and readiness, with separate indicator sets.

EndpointMethodPurpose
/health/liveGETLiveness — is the process healthy enough to keep alive?
/health/readyGETReadiness — is the app ready to receive/process traffic?

Both return 200 with {"status":"UP", ...} when all relevant indicators pass, or 503 with status DOWN otherwise. Liveness stays UP through transient states (startup, shutdown, and license issues a restart can't fix) so orchestrators don't needlessly restart the process; readiness goes DOWN during startup, state restoration, and shutdown.

curl -i localhost:8080/health/live
curl -i localhost:8080/health/ready

The response lists each component indicator (engine state, Kafka broker connectivity, Schema Registry if configured, license state) with its own status and details. See Health checks for the indicators and Probes for wiring them to Kubernetes.

Control

Pause and resume processing at runtime — for maintenance, draining, or controlled investigation.

EndpointMethodPurpose
/pausePOSTPause processing — drains in-flight work, then reaches PAUSED.
/unpausePOSTResume processing — returns to RUNNING.
curl -s -X POST localhost:8080/pause
# -> {"status":"pausing","state":"DRAINING"}

curl -s -X POST localhost:8080/unpause
# -> {"status":"resumed","state":"RUNNING"}

Both are POST. A request that can't be honoured from the current state returns 400 with an explanatory error; if the engine isn't initialised yet you get 503. See Pause and unpause for the state semantics and what "draining" guarantees.

High availability

Registered only when hot standby is enabled (ha.mode != off); otherwise these paths return 404.

EndpointMethodPurpose
/ha/statusGETThis pod's view of the cluster: role, replication lag, ready-standby count, promotion-token epoch, and observed peers.
/ha/switchPOSTSwap roles — the active drains and the peer promotes.
/ha/promotePOSTPromote a specific standby (?pod=<id>).
/ha/demotePOSTDemote a specific active (?pod=<id>).
curl -s localhost:8080/ha/status
curl -s -X POST localhost:8080/ha/switch
# -> {"command":"SWITCH","target":null,"commandOffset":42}

The write endpoints publish a command and return 202 Accepted with the command's offset as an idempotency token; the targeted pod observes it and acts. If no caught-up (READY_STANDBY) target exists, they reject with 409 Conflict — handing off to a not-ready peer is a self-inflicted outage; ?force=true overrides the gate (a forced promotion still fully restores state before processing). See High availability for the operational guide and REST API reference for full response shapes.

License

EndpointMethodPurpose
/licenseGETCurrent runtime license-validation state.

/license reports validation status, tier, expiry and days remaining, machine usage against the allowance, and heartbeat/grace state.

curl -s localhost:8080/license
The response contains customer-identifying fields (licenseId, customerName, machine counts). Treat it as in-cluster only — never expose /license through internet ingress.

The same state also surfaces through the license health indicator (readiness goes DOWN on expired/revoked/invalid licenses) and as metrics. See License configuration.

Metrics

EndpointMethodPurpose
/metricsGETPrometheus text-exposition scrape of JVM and application metrics.
curl -s localhost:8080/metrics

The endpoint serves the Prometheus text format (text/plain; version=0.0.4). It returns 503 if metrics are disabled (runtime.metrics.enabled: false). The full meter catalogue — commit, changelog, restoration, dispatch, and license meters — is in Metrics.

Debug

Two pull-only diagnostic snapshots for investigating a stalled or frozen commit pipeline.

EndpointMethodPurpose
/debug/threadsGETSnapshot of engine-owned and platform thread state and stacks, for freeze diagnosis.
/debug/barriersGETCommit-pipeline snapshot: in-flight commit progress, which lanes are outstanding, and a derived phase summary.

Both are gated by runtime.http.debug.enabled (default true). When disabled, they return 404. They are snapshots of state already kept for other purposes, so there's no cost when nobody is calling them.

# Thread snapshot (optional: depth, filter=all|stuck|known)
curl -s 'localhost:8080/debug/threads?filter=stuck'

# Commit-pipeline snapshot — see the derived phase
curl -s localhost:8080/debug/barriers

/debug/threads accepts optional query params: depth (max stack frames per thread, default 40) and filter (all default, stuck for non-runnable threads, known for engine threads only). /debug/barriers summarises the commit pipeline into a single phase string so you can tell at a glance whether a commit is waiting on lanes, queued, in transaction, or idle.

The debug endpoints expose internal engine state and are meant for diagnosis, not routine monitoring. Leave them on (they're free at rest), but keep them off public ingress. For hardened deployments that limit attack surface, set runtime.http.debug.enabled: false.

Full reference

This page is a tour by use case. For the exhaustive list — every response field, status code, and content-negotiation rule — see the REST API reference.