Telemetry API¶
For whoever maintains the service. If you're putting telemetry in a game, you want Adding it to a game instead — you don't need any of this.
Base URL: https://telemetry.ardenttitanite.com
Auth: X-Telemetry-Key header.
Two keys, and they must differ:
| Key | For | Can |
|---|---|---|
INGEST_KEY |
The games | Write segments, register games |
READ_KEY |
Consumers | Read only |
A leaked read key can't forge activity. That's the point of splitting them.
POST /v1/segments¶
{
"eventId": "a-guid-generated-once-per-batch",
"gameKey": "genesius",
"placeId": "137231719757604",
"jobId": "server-job-id",
"serverTime": 1785735243003,
"segments": [
{
"robloxId": "1234567890",
"username": "Someone",
"team": "Blue",
"startedAt": 1785734043003,
"endedAt": 1785735243003,
"reason": "leave"
}
]
}
| Response | Means |
|---|---|
201 {duplicate: false} |
Stored |
200 {duplicate: true} |
Already had this eventId. Nothing counted twice. |
400 |
Malformed. Retrying won't help. |
403 |
Game isn't registered, or is disabled. |
401 |
Wrong key. |
Reuse eventId when retrying. That's the whole idempotency story — the
sender never has to know whether its first attempt landed.
robloxId is a string. A Roblox ID above 2^53 rounds as a JSON number, and a
rounded ID writes one player's session onto someone else's account.
POST /v1/games¶
Register a game. Holding the ingest key isn't enough to report — a game has to be registered too, so one game can be switched off without rotating everyone's key.
POST /v1/games/:gameKey/disable¶
Stops that game reporting. Its existing records are untouched.
GET /v1/playtime¶
?gameKey=genesius&since=<ms>&until=<ms> — defaults to the last 7 days.
Computed from the raw rows on every request, excluded segments left out. Deliberately not a running total: a total that drifts can't be checked, whereas this can be recomputed and compared against the envelopes it came from.
GET /v1/stats¶
Envelope, segment, excluded and game counts. Good for a health check.
When a segment gets flagged¶
| Reason | Rule |
|---|---|
| ends before it starts | endedAt earlier than startedAt |
| longer than the ceiling | over MAX_SEGMENT_MS, default 12 hours |
| starts in the future | beyond MAX_CLOCK_SKEW_MS, default 6 hours ahead |
| non-numeric timestamps | not a number |
Flagged segments are stored, excluded from totals, and never deleted.
Running it¶
cd ~/titan-telemetry
git pull && npm ci && npm run build
sudo systemctl restart titan-telemetry
sudo journalctl -u titan-telemetry -f
Port 8794 on 127.0.0.1, published by the cloudflared-titan-telemetry tunnel.
Database at ~/titan-telemetry/data/telemetry.sqlite.