HTTP API
The ingestion API is how push-mode integrations (the Minecraft plugin, the SDK, or your own code) send data to Tickr. It’s four endpoints under https://api.tickr.gg/v1.
Authentication
Every request authenticates with a server key (tickr_sk_…), created in the dashboard under Server → Settings → API key, sent as a bearer token:
Authorization: Bearer tickr_sk_xxxxxxxxxxxxxxxx
Keys are scoped to a single server. Revoke and rotate them from the dashboard at any time.
Rate limits & batching
- 600 requests per minute per key. Exceeding it returns
429with aRate limit exceedederror, so back off and retry. - Session and event payloads are batches of 1 to 500 items. Prefer fewer, larger requests over many small ones.
- Timestamps (
ts) are epoch milliseconds from the source machine; values before 2020 or more than 5 minutes in the future are rejected.
POST /v1/ingest/sessions
Records player join/leave activity (world switches are sent as a leave + join pair sharing the sessionId).
{
"batch": [
{
"playerId": "069a79f4-44e9-4726-a5be-fca90e38aaf5",
"username": "Steve",
"type": "join",
"sessionId": "9b2f6dc4-3a1e-4c8e-9f6a-2d1e0b7c5a44",
"world": "bedwars-lobby",
"ts": 1750000000000
}
]
}
| Field | Type | Notes |
|---|---|---|
playerId | string (1-64) | Stable pseudonymous id (UUID, SteamID, etc). Required. |
username | string (≤64) | Optional display name. |
type | "join" | "leave" | Required. |
sessionId | UUID | Required; pairs the join with its leave. |
world | string (≤120) | Optional world / backend server name. |
ts | number | Epoch ms. Required. |
POST /v1/ingest/events
Custom events with optional category, numeric value and free-form properties. Requires a paid plan (see license check).
{
"batch": [
{
"name": "bedwars_win",
"category": "minigame",
"playerId": "069a79f4-44e9-4726-a5be-fca90e38aaf5",
"value": 1,
"properties": { "map": "lighthouse" },
"idempotencyKey": "f3c9a1b2-7d4e-4f08-a6b5-1c2d3e4f5a6b",
"ts": 1750000000000
}
]
}
| Field | Type | Notes |
|---|---|---|
name | string | Required; ^[a-z0-9_:-]{1,64}$ (lowercase snake/kebab). |
category | string (≤64) | Optional grouping such as minigame, economy, … |
playerId | string (≤64) | Optional; omit for server-level events. |
value | number | Optional numeric value (amounts, durations). |
properties | object | Optional free-form JSON properties. |
idempotencyKey | string (8-64) | Required; see below. |
ts | number | Epoch ms. Required. |
Idempotency
Network retries must never double-count an event. Each event carries a client-generated idempotencyKey (a random UUID is fine); if Tickr has already accepted an event with the same key for this server, the duplicate is silently skipped. This makes the safe retry strategy trivial: resend the whole batch on any failure. Already-ingested items are deduplicated, missing items are stored. The SDK and plugin auto-generate keys for you.
POST /v1/ingest/heartbeat
A small, unbatched liveness ping. Send one every ~30 seconds:
{ "tps": 19.97, "cleanShutdown": false }
| Field | Type | Notes |
|---|---|---|
tps | number (0-1000) | Optional current tick rate. |
cleanShutdown | boolean | Optional; send true as the final heartbeat of a graceful stop. |
Heartbeats power crash detection: if a server goes silent without a cleanShutdown: true heartbeat, the downtime is classified as a crash and shows up in post-mortems; with it, it’s a clean restart.
GET /v1/ingest/license
Returns the entitlements of the plan behind this server key:
{ "premium": true, "plan": "pro" }
Use it to gate premium-only features (like custom events) client-side instead of sending payloads that will be rejected. The plugin polls this every 10 minutes so plan upgrades apply without a restart.
Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid server key. |
422 | Validation failed; response body lists the offending fields. |
429 | Rate limit exceeded (600 req/min/key); back off and retry. |
5xx | Transient server error; retry with exponential backoff. |