Read the product metrics, and the ones putty cannot yet compute
Every metric `build-plan-artsy.md` §8 names, as one of two shapes. **`measured[]`** carries a number, the definition of what that number counts, the window it covers, and the table it was read from. `value` on a money metric is the count of ledger ENTRIES; the amount is `amountUsd`, a decimal string, because the column is `TEXT` and the sum is computed in Postgres' `NUMERIC` rather than in JavaScript. A `value: 0` with a `sourceRows: 0` is a real measurement of an empty table — a genuine zero, not a gap. **`notComputable[]`** carries no number. It names the specific missing data in `missing[]` and says why in `reason`. **A metric in this list is not a zero**, and rendering it as `0` claims that nobody did the thing, when the truth is that putty has not recorded whether they did. Today this list holds seven of §8's nine metrics, including the north star: `north_star_monthly_active_projects` needs a record of a project *changing* after creation, and no table in this schema stores one. **Availability is not a zero either.** If a measured metric's query fails, this route answers `500` rather than quietly downgrading that metric to `not_computable`, so a database outage never reads as a claim about the product. **Coverage on `launches_by_venue`.** A row is written when a launch is *requested* (`status: "awaiting_signature"` at create), so the counts are launch *attempts* by venue, not successful launches. Only `erc20-direct` — putty's own rail — can produce a row today: `pons-v2`, `hookr`, `orbio` and `venue-adapter` are registered providers that throw `ProviderBlockedError` from `buildLaunch`, so a launch through them is refused before a row exists. Every registered venue is listed, and a blocked venue is reported at zero *with its reason*, so a blocked rail is never presented as a rail nobody chose. Read `coverageNote` on the metric. **This is not `src/modules/observability/`.** That module is distributed tracing — Sentry spans for latency and the operator's health view. A span is one timed operation, not a count of anything a user did, and no metric here is answered from one. **The window.** Omit `days` for all time, which is the default and the honest one: on a young deployment a 30-day window is a window over very few rows, and a number computed from three reads like a rate. Every metric in the response is read over the same window, and each entry repeats it so it stays meaningful on its own. **Public and unauthenticated.** These are aggregate counts over rows this platform wrote about itself, and §5's Leg 2 asks for the buyback figure to be visible. No metric here names a user, an address, or a token. The operator's own health view is a different route behind a different gate: `GET /operator`.
Every metric build-plan-artsy.md §8 names, as one of two shapes. measured[] carries a number, the definition of what that number counts, the window it covers, and the table it was read from. value on a money metric is the count of ledger ENTRIES; the amount is amountUsd, a decimal string, because the column is TEXT and the sum is computed in Postgres' NUMERIC rather than in JavaScript. A value: 0 with a sourceRows: 0 is a real measurement of an empty table — a genuine zero, not a gap. notComputable[] carries no number. It names the specific missing data in missing[] and says why in reason. A metric in this list is not a zero, and rendering it as 0 claims that nobody did the thing, when the truth is that putty has not recorded whether they did. Today this list holds seven of §8's nine metrics, including the north star: north_star_monthly_active_projects needs a record of a project changing after creation, and no table in this schema stores one. Availability is not a zero either. If a measured metric's query fails, this route answers 500 rather than quietly downgrading that metric to not_computable, so a database outage never reads as a claim about the product. Coverage on launches_by_venue. A row is written when a launch is requested (status: "awaiting_signature" at create), so the counts are launch attempts by venue, not successful launches. Only erc20-direct — putty's own rail — can produce a row today: pons-v2, hookr, orbio and venue-adapter are registered providers that throw ProviderBlockedError from buildLaunch, so a launch through them is refused before a row exists. Every registered venue is listed, and a blocked venue is reported at zero with its reason, so a blocked rail is never presented as a rail nobody chose. Read coverageNote on the metric. This is not src/modules/observability/. That module is distributed tracing — Sentry spans for latency and the operator's health view. A span is one timed operation, not a count of anything a user did, and no metric here is answered from one. The window. Omit days for all time, which is the default and the honest one: on a young deployment a 30-day window is a window over very few rows, and a number computed from three reads like a rate. Every metric in the response is read over the same window, and each entry repeats it so it stays meaningful on its own. Public and unauthenticated. These are aggregate counts over rows this platform wrote about itself, and §5's Leg 2 asks for the buyback figure to be visible. No metric here names a user, an address, or a token. The operator's own health view is a different route behind a different gate: GET /operator.
Query Parameters
Measure over the trailing N days, ending now: [now - N days, now). Omit for all time. A trailing window is a genuine measurement like any other, but on a young deployment it is a window over very few rows, and the row count is on the metric so you can see that for yourself.
0 < value <= 3650Response Body
application/json
application/json
application/json
curl -X GET "https://example.com/metrics"{ "generatedAt": "string", "window": { "kind": "all_time", "from": "string", "to": "string" }, "measured": [ { "status": "measured", "metric": "string", "definition": "string", "window": { "kind": "all_time", "from": "string", "to": "string" }, "source": "string", "value": 0, "sourceRows": 0, "amountUsd": "string", "byVenue": [ { "venue": "string", "launches": 0, "available": true, "blockedReason": "string" } ], "coverageNote": "string" } ], "notComputable": [ { "status": "not_computable", "metric": "string", "definition": "string", "wanted": "string", "missing": [ "string" ], "reason": "string" } ], "coverage": { "measured": 0, "notComputable": 0, "total": 0 }}Check liveness GET
Reports whether the process is serving traffic. It performs no dependency checks, so a 200 means the API answered, not that its downstreams are healthy.
Read the operator overview GET
A single read-only snapshot of the platform: dependency health, the run queue's depth, every active run with the age of its lease, and the buyback amount owed. `buyback.owedUsd` is a decimal string summing `RevenueEntry.buybackShareUsd` over the whole ledger, which is the spec's record of the share every payment marks (`prompt.md:1610-1612`). Execution of a buyback is manual and timing-discretionary per `tokenomics.md`; this route only reports the obligation. It is a string rather than a number because the column is `TEXT` and dollar amounts are never summed as floats. **Authorization.** Send the operator token as a bearer: `Authorization: Bearer $OPERATOR_TOKEN`. A request with no token is `401`; a token that is not the operator token is `403`. When `OPERATOR_TOKEN` is unset the route refuses every caller, including one holding a valid Privy session — it denies by default rather than falling back to a permissive check.