The HTTP API in five minutes
Everything the console and the MCP tools do goes through the daemon’s HTTP API — this guide drives
the whole loop with curl: create a source, feed it, read a correlated timeline, define a trigger,
watch it fire, and write an observation back. No upstream systems required.
You need a running daemon (Quickstart): navflow up, API at http://127.0.0.1:8787.
Ingest — create a source and feed it
Create a push (webhook) source. The config maps payload fields into the
envelope; the label marked primary is the entity key:
curl -s -XPOST localhost:8787/api/sources -H 'content-type: application/json' -d '{
"name": "checkout_probe",
"connector": "webhook",
"config": {
"event_type": "probe",
"text_template": "latency {latency_ms}ms on {endpoint}",
"labels": [{ "name": "service", "field": "service", "primary": true }]
}
}'
# {"ok":true,"name":"checkout_probe","ingest_key":"webhook-…"}Feed it:
curl -s -XPOST localhost:8787/ingest/checkout_probe -H 'content-type: application/json' \
-d '{"service": "checkout", "endpoint": "/pay", "latency_ms": 120}'
curl -s -XPOST localhost:8787/ingest/checkout_probe -H 'content-type: application/json' \
-d '{"service": "checkout", "endpoint": "/pay", "latency_ms": 1450}'
curl -s -XPOST localhost:8787/ingest/checkout_probe -H 'content-type: application/json' \
-d '{"service": "search", "endpoint": "/q", "latency_ms": 45}'Numeric payload fields (latency_ms) become typed fields triggers can aggregate over; the full
payload is kept lossless. This is the generic inbound path for anything that can send JSON.
Locally you can post to the source by name. The response’s ingest_key is the stable, unguessable
path (/ingest/<ingest_key>) — use that (plus NAVFLOW_INGEST_TOKEN)
when producers deliver over the network.
Read — one correlated timeline
The primary read needs no setup at all — a {label: value} selector across all sources:
curl -s -XPOST localhost:8787/read -H 'content-type: application/json' \
-d '{"selector": {"service": "checkout"}, "window": "15m"}'You get checkout’s events, time-ordered, from every source that carries the label — with one
source it’s modest; the payoff is when logs, metrics, and commits arrive interleaved on one clock.
To fix the source set and reuse it (and to attach triggers), save a view and query through it:
curl -s -XPOST localhost:8787/api/views -H 'content-type: application/json' -d '{
"name": "service_health",
"key_field": "service",
"sources": ["checkout_probe"]
}'
curl -s -XPOST localhost:8787/query -H 'content-type: application/json' \
-d '{"view": "service_health", "key": "checkout", "window": "15m"}'Watch — a trigger that wakes someone
Start a subscriber to be woken (stands in for your agent’s webhook) in a second terminal —
examples/woke_receiver.py
in the repo listens on http://127.0.0.1:9999/woke. Then define the condition and subscribe it:
curl -s -XPOST localhost:8787/api/triggers -H 'content-type: application/json' -d '{
"name": "slow_checkout",
"view": "service_health",
"condition": {"aggregate": "max", "field": "latency_ms", "predicate": "> 1000", "window": "5m"},
"emit": {"kind": "slow_checkout", "context_window": "15m"},
"cooldown": "1m"
}'
curl -s -XPOST localhost:8787/subscribe -H 'content-type: application/json' \
-d '{"trigger": "slow_checkout", "url": "http://127.0.0.1:9999/woke"}'Cause the condition:
curl -s -XPOST localhost:8787/ingest/checkout_probe -H 'content-type: application/json' \
-d '{"service": "checkout", "endpoint": "/pay", "latency_ms": 2100}'Within a few seconds the receiver prints the dispatch — with the 15-minute correlated timeline attached. That’s the core move: the store wakes the agent, and the agent starts with context instead of fetching it. Every firing (even with zero subscribers) is logged:
curl -s localhost:8787/api/activity/dispatches(console: Agents → Trigger dispatches.)
Write back — the agent surface over HTTP
The MCP tools map onto the same endpoints, so you can drive the agent loop by hand. Describe an object — inferred schema, entities, freshness, sample events:
curl -s localhost:8787/catalog/source:checkout_probeDerive a view the way an agent would (it lands in the catalog tagged with its creator):
curl -s -XPOST localhost:8787/derive -H 'content-type: application/json' -d '{
"sources": ["checkout_probe"], "key_field": "service", "name": "slow_only",
"filters": [{"field": "latency_ms", "op": "gt", "value": 1000}]}'Write an observation back — the first call auto-provisions the
agent_memory source, and the memory shows up inside the entity’s timeline
on the next read:
curl -s -XPOST localhost:8787/remember -H 'content-type: application/json' \
-d '{"key": "checkout", "content": "latency spikes on /pay correlate with payments deploys"}'To do all of this from a real agent instead, connect one over MCP — the tool set
(read, query, catalog_list / catalog_describe, derive, remember, subscribe, plus the
source-setup tools) is this API with discovery built in.
Keep it — the catalog as YAML
Everything you just built is catalog state; YAML is its portable form:
curl -s localhost:8787/api/catalog/export > catalog.yaml # git it, share itImporting (console → Catalog, or POST /api/catalog/import) supports merge or replace,
validated as a whole before anything is written. A fresh daemon pointed at that YAML
(NAVFLOW_CATALOG=catalog.yaml navflow up) reproduces the whole setup on first boot.