Skip to Content
TaresGuidesThe HTTP API in five minutes

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): tares 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 when producers deliver over the network. On a secured instance, producers also send an ingest-scoped API key as Authorization: Bearer <key>.

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 read only some sources, name them with sources, or name a project to read only that project’s sources:

curl -s -XPOST localhost:8787/read -H 'content-type: application/json' \ -d '{"selector": {"service": "checkout"}, "window": "15m", "sources": ["checkout_probe"]}'

Watch: a trigger that wakes someone

A trigger names the sources it watches, the label that identifies the entity, and the condition. 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", "sources": ["checkout_probe"], "key_field": "service", "condition": {"aggregate": "max", "field": "latency_ms", "predicate": "> 1000", "window": "5m"}, "emit": {"kind": "slow_checkout", "context_window": "15m"}, "cooldown": "1m" }' # {"ok":true,"project":"uc_…"} 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: Firings.)

See it in the project

You named no project, so the source and the trigger landed in the Default project, the one GET /api/projects lists first. Its timeline shows the firing as a thread, with where it was delivered:

curl -s localhost:8787/api/projects/uc_…/timeline # the project id the trigger call returned

(console: Projects → Default → Setup → Advanced setup → Activity.) To keep a job separate, create a project first and pass its id or name as project when you create the source and the trigger. See Projects.

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_probe

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, catalog_list / catalog_describe, create_trigger, 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 it

Importing (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 (TARES_CATALOG=catalog.yaml tares up) reproduces the whole setup on first boot.

Last updated on