Skip to content
MeridFlow AiFlow v8.x • self-hosted

Live architecture

A single reading of what this deployment is doing right now: which entry points are carrying sessions, how many are in flight against the licence ceiling, and what has happened in the last few minutes. This is what backs the admin dashboard's Live architecture page.

Where Analytics answers "how did last month go", this answers "what is happening this second", so it is deliberately narrow: a short window, a capped result, and no history.

Reading the board

The dashboard draws this endpoint as a single connected diagram rather than a list of counters. Work arrives at the entry nodes on the left, passes through the core, is handled by the ring of nodes around it, and leaves as an outcome on the right.

A node's brightness follows its load, and a node holding a live session pulses. Each connection carries moving traffic in proportion to the activity on the node that drives it, so a busy path is visibly busier. An idle connection stays faintly drawn, because the shape of the deployment is worth seeing even when nothing is moving through it.

The number inside a node is what is live there now; the figure beneath it is what passed through inside the window. The core shows the deployment's total in-flight sessions, which is the same number the capacity reading above the board reports.

The board honours prefers-reduced-motion: with that setting on, every pulse stops and the diagram renders still.

Endpoint

GET /api/v1/telemetry

Mounted only when the licence grants analytics. On a plan without it the path returns 404 rather than 403, so a locked surface is indistinguishable from one that was never built.

Authentication and roles

Takes an admin session token (see Authentication). Any role can call it, including Viewer, the same read-only bar as the Calls log.

Query parameters

Parameter Type Description
window_minutes integer How far back the activity feed and the recent counts look. 1 to 1440, default 60.
curl "https://api.your-domain.com/api/v1/telemetry?window_minutes=15" \
  -H "Authorization: Bearer $ADMIN_TOKEN"
import httpx

response = httpx.get(
    "https://api.your-domain.com/api/v1/telemetry",
    params={"window_minutes": 15},
    headers={"Authorization": f"Bearer {admin_token}"},
)
response.raise_for_status()
telemetry = response.json()
{
  "generated_at": "2026-08-29T10:00:00Z",
  "window_minutes": 60,
  "capacity": { "live_sessions": 2, "limit": 25, "at_capacity": false },
  "nodes": [
    { "id": "widget", "live": 1, "recent": 14 },
    { "id": "phone", "live": 1, "recent": 31 },
    { "id": "agents", "live": 2, "recent": 45 },
    { "id": "memory", "live": 0, "recent": 38 }
  ],
  "events": [
    {
      "id": "call-912",
      "at": "memory",
      "stage": "CALL",
      "action": "call.finished",
      "detail": "Completed on channel phone, transcript stored.",
      "occurred_at": "2026-08-29T09:58:12Z"
    }
  ]
}

Fields

Field Type Description
generated_at string When the reading was taken, so a stale poll is visible as stale.
window_minutes integer Echoed back, since the server clamps out-of-range values.
capacity object Concurrency in flight against the licence. See below.
nodes array Every board node, always all twelve, zero-filled rather than omitted.
events array Up to 60 recent sessions, newest first, already resolved to a node.

capacity

Field Type Description
live_sessions integer Sessions currently ringing or in_progress on a metered channel.
limit integer or null The concurrent_calls ceiling, or null on a plan that does not meter it.
at_capacity boolean Whether one more session would be refused.

limit is null for unmetered rather than a large number, so a client renders "unmetered" instead of drawing a bar that is permanently near empty. Treating null as zero would draw it permanently full, which is the opposite of what it means.

Only phone and web count toward live_sessions. A background task or an inbound email holds no line, so metering them would refuse real callers to protect capacity nothing is using.

nodes

Every node reports two counts. live is what is sitting there right now, which is what the dashboard lights up. recent is what passed through inside the window.

The identifiers are a presentation contract shared with the public simulator on the MeridFlow site, so the same diagram renders whether it is driven by a script or by real traffic. Renaming one is a breaking change for that view even though nothing in the database refers to it.

Group Node ids
Entry widget, phone, events, mailbox
Deployment core
Intelligence agents, orchestrators, knowledge, tools
Outcome response, continuity, memory

events

A session is reported at the node its current state belongs to rather than at the door it came in through, so the board lights up along the whole path instead of only on the left.

Call status Reported at action
ringing, in_progress agents call.in_progress
transferred response call.transferred
completed memory call.finished
failed, no_answer, busy entry node call.<status>
pending entry node call.started

Cost and polling

The endpoint aggregates directly off Call with no rollup pipeline, the same approach the analytics endpoints take. The window bounds the scan and the feed is capped at 60 rows, so cost does not grow with accumulated history.

The dashboard polls every two seconds. Polling faster buys nothing: a session lasts minutes, and the underlying rows do not change more often than that.

Next

  • Analytics: aggregate trends over a date range, rather than a live reading.
  • Calls: the per-session record every count here is derived from.