Runners & Apps API

See which apps and runners are live right now - they appear because a runner registered itself, with its self-reported metadata attached.

The read-only runners and apps API backs the console's Apps view. It reflects live registrations - apps and runners appear because a runner registered, not because anything was configured by hand. There is no write surface here: runners register themselves through the SDK handshake (see runners).

Method + pathReturns
GET /appsThe project's registered apps.
GET /runnersThe project's registered runner endpoints, with metadata and liveness.

GET /apps

Lists every app that has registered in the project, ordered by name.

FieldMeaning
nameThe app name.
createdAtWhen the app was first seen (ISO 8601).
import { createClient } from "@duraton/sdk/client";

const duraton = createClient({ url: process.env.DURATON_URL! });
const apps = await duraton.apps.list(); // App[]

GET /runners

Lists the registered runner endpoints. Pass ?app=<name> to scope to one app; omit it for every app in the project.

ParamMeaningDefault
appRestrict to one app.all apps

Each runner carries the metadata it reported on register. Optional fields are present only when the runner actually reported them (a runner predating a field, or one that left it unset, omits it).

FieldMeaning
runnerIdThe runner's stable id, or its URL when it registered without one.
appThe app this runner hosts.
urlThe invoke endpoint, or a conn:// pseudo-URL for a connect (WebSocket) runner.
frameworkThe serve adapter in use (hono, express, next, fastify, bun, elysia, node), or connect.
runtimeThe JS runtime: node, bun, or deno.
sdkName + versionThe SDK package and version.
regionThe deployment region, when DURATON_REGION is set.
keyFingerprintA one-way SHA-256 prefix of the runner's invoke signing key (never the key).
keyMatchcurrent, previous or mismatch, classifying the runner's signing key against the ones Duraton holds; omitted when the comparison is not possible (either side has no key). previous means the runner is still on the key it had before a rotation.
lastSeenAtWhen Duraton last saw this runner (ISO 8601): its last re-registration for a serve runner, its last socket heartbeat for a conn:// one. Either way it advances roughly every 30s while the runner is healthy.
liveWhether lastSeenAt is inside the 90s liveness window. The rule is the same for both transports, so a conn:// runner whose process is gone reports live: false once it falls behind. A runner past the window is listed, not hidden.

See runner liveness for what refreshes lastSeenAt on each transport, and what a live: false runner means for routing.

Responses never include a signing key or secret - only the one-way keyFingerprint.

import { createClient } from "@duraton/sdk/client";

const duraton = createClient({ url: process.env.DURATON_URL! });
const runners = await duraton.runners.list({ app: "shop" }); // Runner[]
[
  {
    "runnerId": "gateway-1",
    "app": "shop",
    "url": "https://shop.example.com/api/duraton/invoke",
    "framework": "hono",
    "runtime": "node",
    "sdkName": "@duraton/sdk",
    "version": "0.1.0",
    "region": "us-east-1",
    "keyFingerprint": "7f3a1b2c4d5e",
    "keyMatch": "current",
    "lastSeenAt": "2026-06-25T10:30:00Z",
    "live": true
  }
]

On this page