Metadata endpoints
Numbers alone do not carry what a team knows. These three endpoints are where that knowledge goes: a note on a spike, a definition of a name only your project uses, a question worth re-asking with the answer it got.
| Table | What it holds |
|---|---|
annotations |
Notes pinned to the project, a scene, a mesh, a region, a metric, or a period of time. |
glossary |
What a name means in this project — a mesh name, a scene id, a custom event, a shorthand. |
saved_analyses |
A titled question plus the conclusion drawn from it, so it need not be re-derived. |
Endpoints
Section titled “Endpoints”| Method | Path | Purpose | Capability |
|---|---|---|---|
GET |
/api/v1/annotations |
The project’s notes, newest first. | query |
POST |
/api/v1/annotations |
Leave a note. Answers 201 with the stored row. |
annotate |
DELETE |
/api/v1/annotations/:id |
Remove a note. 204, or 404 if it is not there. |
annotate |
GET |
/api/v1/glossary |
The whole glossary, ordered by term. | query |
PUT |
/api/v1/glossary/:term |
Define (or redefine) a term — idempotent. | annotate |
DELETE |
/api/v1/glossary/:term |
Undefine a term. | annotate |
GET |
/api/v1/analyses |
Saved analyses, newest first. | query |
POST |
/api/v1/analyses |
Save an analysis. Answers 201. |
annotate |
DELETE |
/api/v1/analyses/:id |
Remove a saved analysis. | annotate |
# A note about a period of timecurl -X POST -H "x-api-key: $KEY" -H "content-type: application/json" \ -d '{"targetKind":"window","since":1757000000000,"until":1757003600000, "text":"CDN incident — ignore the load-time spike here."}' \ "https://collect.example.com/api/v1/annotations"
# What a mesh name means in this projectcurl -X PUT -H "x-api-key: $KEY" -H "content-type: application/json" \ -d '{"meaning":"the till cluster by the exit"}' \ "https://collect.example.com/api/v1/glossary/checkout%20counter"
# A question worth keepingcurl -X POST -H "x-api-key: $KEY" -H "content-type: application/json" \ -d '{"title":"Lobby FPS after the lighting change", "query":{"metric":"perf_summary","scene":"lobby"}, "conclusion":"p50 fell from 58 to 41 on integrated GPUs."}' \ "https://collect.example.com/api/v1/analyses"An annotation’s target
Section titled “An annotation’s target”targetKind is one of project, scene, mesh, region, metric or window. The four middle
ones name something and need a targetId (the scene id, mesh name, region id or metric id);
window needs a since; project is a standing note about everything.
since/until are epoch milliseconds. On a read they are an overlap filter — a note matches
when its period intersects the requested window, and a standing note always matches, because it is
about the project rather than about a moment.
Who wrote it
Section titled “Who wrote it”Every stored row carries authorKind (user or agent) and authorKeyId (the key’s row id, never
the key itself). The collector decides authorKind from the calling client, never from the payload:
a request carrying x-uptimizr-client: dashboard — a person clicking in a first-party UI — is
user; everything else holding an annotate key, including the in-browser assistant writing up its
own answer, is agent.
Bounds
Section titled “Bounds”Free text is capped at the boundary — text ≤ 2 000 characters, meaning ≤ 500, title ≤ 120,
conclusion ≤ 4 000, and a saved query document ≤ 8 000 serialized characters. Each project holds
at most 500 annotations, 200 glossary terms and 200 saved analyses. A write past a cap answers
409: the payload was fine, the project is full — delete something and retry.
query on a saved analysis is an opaque JSON object: the collector stores it and does not
interpret it. Put the endpoint and filters that produced the answer in it, so the next reader can
re-run what you actually ran.
Privacy
Section titled “Privacy”These rows are written by your own operators and agents, not captured from visitors, so they are the one place in the collector that is not machine-bounded to non-PII. They are project-scoped, readable only with that project’s key, bounded in size and count, and audited — but do not paste personal data into them. See Privacy & configuration.
From an agent
Section titled “From an agent”@uptimizr/mcp exposes the same three writes as the MCP tools annotate, define_term and
save_analysis, plus list_annotations, list_glossary and list_analyses. They are registered
only when the configured key holds annotate — the server asks GET /api/v1/whoami once at
start-up — so a read-only key yields a read-only server. See
MCP server and Building agents on Uptimizr.