Metrics API
Read-only HTTP API for OBS browser sources, stream widgets, and public sites.
No wallet login - only a per-project lb_live_ key.
Full endpoint list:
API reference.
@latrinebot/sdk
or the
@latrinebot/cli
for cron / CI.
import { LatrineClient } from "@latrinebot/sdk";
const client = new LatrineClient({ metricsKey: process.env.LATRINE_METRICS_KEY });
const snap = await client.metrics.get(process.env.PROJECT_ID);
console.log(snap.stats.totalClaimedSol, "SOL claimed");
Or from the shell:
npx @latrinebot/cli status <project-id>
Full setup in the Developers guide.
Get a key
- Open the dashboard and select your project.
- Scroll to Metrics API.
- Click Generate key. Copy the value immediately - it is shown once.
Keys look like lb_live_ plus 48 hex characters. Store them like a password. Revoke in the dashboard if leaked.
Base URL
https://api.latrinebot.com
Authentication
Send the key on every request:
X-Metrics-Key: lb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Wrong or missing keys return 401.
Token CA and ticker
The Metrics API exposes your token identity for overlays. Use these fields to print labels, links to Pump.fun / Dexscreener, or custom graphics.
| Field | Location in response | Notes |
|---|---|---|
mint |
Top level | Contract address (CA), base58. Same as settings.mint. |
settings.tokenSymbol |
Inside settings |
Ticker without $ (example: LATRINE).
Set by the server from DexScreener when the mint is saved in the dashboard.
Empty string if not resolved yet.
|
There is no separate top-level ticker field on Metrics API responses.
Always read settings.tokenSymbol.
Tiers and hold cycles
| Field | Location | Notes |
|---|---|---|
settings.eligibilityTiers |
settings |
Full tier table configured in the dashboard. Each row: mcUsd, minTokens, holdCycles. |
activeTier |
Top level | Last LIVE cycle: which tier was active and its holdCycles requirement. null if no LIVE cycle yet. |
stats.lastTierMcUsd |
stats |
Same tier as activeTier.mcUsd when set. |
stats.lastTierMinTokens |
stats |
Minimum balance floor for that tier, in whole tokens. |
stats.lastTierHoldCycles |
stats |
Consecutive cycles required in-band before a wallet is paid (anti-sybil). |
// Example label in your overlay
const sym = data.settings?.tokenSymbol;
const label = sym ? `$${sym}` : (data.mint ? data.mint.slice(0, 4) + "..." : "-");
document.getElementById("ticker").textContent = label;
To look up a symbol before creating a project (dashboard session, not metrics key):
GET /api/projects/symbol?mint=CA - see
API reference.
GET /api/v1/projects/:projectId/metrics
Returns a JSON snapshot for public overlays.
Stats policy: stats are mainnet LIVE counters only. Test or simulation counters are never included (missing values are 0). The mode field is informational; client dashboards always run LIVE on mainnet.
For the same 6 tiles shown on the token page (Airdrops sent, To holders (SOL est.), Holders paid,
Eligible now, Tokens burned, Creator fees claimed), use publicStats from either:
/api/public/realm/:id/live (token page) or /api/public/widgets/:widgetId/live (embeds).
The realm live payload also includes poolSplit, holdFund (goal mode or Dex Vault), policyHistory, and perk flags - see Distribution transparency API.
Response fields
ok,projectId,updatedAtdataTrust- alwaysliveforstatsmode- usuallyLIVEfor client projects (does not changestats)running- scheduler on or offmint- token CAsettings- public settings includingtokenSymbolandeligibilityTiers(each row:mcUsd,minTokens,holdCycles). No secrets, no operator-only fields.stats- LIVE counters (see API reference)activeTier- last LIVE cycle tier snapshot:mcUsd,minTokens,holdCycles(ornullbefore first LIVE cycle)lastEvent- latest LIVE-cycle log line (test/simulation lines excluded)overlayHint- short note about LIVE-only stats
Example response (truncated)
{
"ok": true,
"projectId": "uuid",
"running": true,
"mode": "LIVE",
"dataTrust": "live",
"mint": "So11111111111111111111111111111111111111112",
"settings": {
"mint": "So11111111111111111111111111111111111111112",
"tokenSymbol": "LATRINE",
"cycleIntervalSec": 60,
"minHolderBalance": 500000,
"eligibilityTiers": [
{ "mcUsd": 0, "minTokens": 500000, "holdCycles": 5 },
{ "mcUsd": 50000, "minTokens": 450000, "holdCycles": 6 },
{ "mcUsd": 100000, "minTokens": 400000, "holdCycles": 8 },
{ "mcUsd": 250000, "minTokens": 300000, "holdCycles": 10 },
{ "mcUsd": 500000, "minTokens": 220000, "holdCycles": 12 },
{ "mcUsd": 1000000, "minTokens": 150000, "holdCycles": 15 },
{ "mcUsd": 2500000, "minTokens": 110000, "holdCycles": 22 },
{ "mcUsd": 5000000, "minTokens": 75000, "holdCycles": 30 },
{ "mcUsd": 10000000, "minTokens": 55000, "holdCycles": 40 },
{ "mcUsd": 15000000, "minTokens": 40000, "holdCycles": 50 },
{ "mcUsd": 25000000, "minTokens": 30000, "holdCycles": 60 },
{ "mcUsd": 50000000, "minTokens": 22000, "holdCycles": 80 },
{ "mcUsd": 100000000, "minTokens": 15000, "holdCycles": 100 }
]
},
"stats": {
"cycles": 42,
"totalClaimedSol": 1.25,
"uniqueHoldersPaidCount": 88,
"lastMarketCapUsd": 125000,
"lastTierMcUsd": 0,
"lastTierMinTokens": 500000,
"lastTierHoldCycles": 5
},
"activeTier": {
"mcUsd": 0,
"minTokens": 500000,
"holdCycles": 5
},
"lastEvent": { "tag": "OK", "body": "...", "at": "..." }
}
curl -s -H "X-Metrics-Key: YOUR_KEY" \
"https://api.latrinebot.com/api/v1/projects/PROJECT_ID/metrics"
GET /api/v1/projects/:projectId/events
Recent public event lines for a scrolling feed. LIVE-cycle lines only (same filter as metrics).
- Query
limit- default 50, maximum 100. - Each item:
tag,body,severity,at
curl -s -H "X-Metrics-Key: YOUR_KEY" \
"https://api.latrinebot.com/api/v1/projects/PROJECT_ID/events?limit=20"
Example (browser overlay)
const API = "https://api.latrinebot.com";
const PROJECT_ID = "your-project-uuid";
const METRICS_KEY = "lb_live_...";
async function poll() {
const res = await fetch(`${API}/api/v1/projects/${PROJECT_ID}/metrics`, {
headers: { "X-Metrics-Key": METRICS_KEY },
});
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
const sym = data.settings?.tokenSymbol;
document.getElementById("ticker").textContent =
sym ? `$${sym}` : "-";
document.getElementById("status").textContent =
data.lastEvent?.body ?? "Waiting...";
document.getElementById("mc").textContent =
data.stats?.lastMarketCapUsd != null
? `$${Math.round(data.stats.lastMarketCapUsd).toLocaleString()}`
: "-";
const tier = data.activeTier;
document.getElementById("hold").textContent =
tier?.holdCycles != null ? `${tier.holdCycles} cycles` : "-";
}
setInterval(poll, 5000);
poll();
Example (token page tiles via publicStats)
For the exact 6 token page tiles, call the public realm endpoint and read stats from its response.
This does not require a metrics key.
const API = "https://api.latrinebot.com";
const PROJECT_ID = "your-project-uuid";
async function pollTokenTiles() {
const res = await fetch(`${API}/api/public/realm/${PROJECT_ID}/live`, { cache: "no-store" });
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
const s = data.stats || {};
document.getElementById("airdrops").textContent = String(s.airdropsCount ?? "-");
document.getElementById("toHolders").textContent = (s.totalDistributedSol ?? 0).toFixed(3);
document.getElementById("holders").textContent = String(s.uniqueHoldersPaid ?? "-");
document.getElementById("eligible").textContent = s.lastEligibleCount != null ? String(s.lastEligibleCount) : "-";
document.getElementById("burned").textContent = s.burnedDisplay || "-";
document.getElementById("claimed").textContent = (s.totalClaimedSol ?? 0).toFixed(3);
}
Dashboard API vs Metrics API
| Metrics API | Dashboard API | |
|---|---|---|
| Auth | X-Metrics-Key | Authorization: Bearer (wallet, Google, or X session) |
| Use in | OBS, public sites | Dashboard app only |
| Control bot | No | Yes (start/stop/settings) |
| Stats | LIVE mainnet only | Dashboard stats for project mode (client projects: LIVE) |
| Preflight | No | GET .../preflight before start |
| Ticker | settings.tokenSymbol | project.settings.tokenSymbol |
See API reference for all dashboard routes.
Homepage live block (no key)
GET /api/public/latrine/live powers the $LATRINE block on
latrinebot.com. Separate from per-project metrics keys; may include
mint and ticker for the showcase token.
Holder perks on public pages (no key)
The token page (/realm/:projectId) and homepage perks panels use additional
public routes (no metrics key, no dashboard session):
reward-options, reward-preference, and social-claim
under /api/public/realm/:id/... or /api/public/latrine/....
They do not expose dev secrets or raw stats buckets.
Full payloads: Holder perks API.