API Reference
All endpoints below use this prefix:
/api/public/v1
Auth header for every call:
Authorization: Bearer <token>
Example environment used across commands:
export BASE_URL="https://highlights-api.rankacy.com"
export TOKEN="rk_live_..."
Pagination pattern
List endpoints use:
limit(bounded per endpoint)offset
Response format:
{
"items": [...],
"pagination": {
"total": 120,
"limit": 20,
"offset": 40
}
}
Demos endpoints
| Method | Path | Description |
|---|---|---|
POST |
/demos/upload |
Upload .dem file |
GET |
/demos |
List demos |
GET |
/demos/{demo_id} |
Demo detail |
GET |
/demos/{demo_id}/kills |
Parsed kill feed |
POST /demos/upload
Request: multipart form-data
file(required):.dem
curl -X POST "$BASE_URL/api/public/v1/demos/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@$DEMO_FILE"
Response 202:
{
"demo_id": 52,
"status": "queued",
"auto_highlight_requested": false,
"was_already_processed_successfully": false,
"user_demo_assignment": "newly_assigned"
}
Upload response fields:
status:queuedfor newly created demo; otherwise existing demo status (new|processing|success|failed)was_already_processed_successfully:truewhen this upload matched an existing demo that was already inSUCCESSuser_demo_assignment:newly_assignedwhen this call created the user<->demo link,already_assignedwhen link already existed
GET /demos
Query params:
created_from(ISO datetime)created_to(ISO datetime)mapstatus(NEW|PROCESSING|SUCCESS|FAILED)upload_type(MANUAL|API)searchlimit(1..100)offset(>=0)
curl -G "$BASE_URL/api/public/v1/demos" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "map=mirage" \
--data-urlencode "status=SUCCESS" \
--data-urlencode "limit=20" \
--data-urlencode "offset=0"
GET /demos/{demo_id}
curl "$BASE_URL/api/public/v1/demos/$DEMO_ID" \
-H "Authorization: Bearer $TOKEN"
GET /demos/{demo_id}/kills
Query params:
roundattacker_steam_id(SteamID64 string)victim_steam_id(SteamID64 string)limit(1..500)offset
Response note:
attacker_steam_idandvictim_steam_idare returned as strings (BIGINT-safe serialization).
curl -G "$BASE_URL/api/public/v1/demos/$DEMO_ID/kills" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "attacker_steam_id=76561198000000000" \
--data-urlencode "round=8" \
--data-urlencode "limit=50"
Response shape:
{
"items": [
{
"demo_kill_id": 801,
"demo_id": 52,
"tick": 15423,
"round": 8,
"attacker_steam_id": "76561198000000000",
"victim_steam_id": "76561198000000001",
"weapon": "ak47",
"item_id": 7,
"is_headshot": true,
"score": 9.5
}
],
"pagination": {"total": 1, "limit": 50, "offset": 0}
}
Highlights endpoints
| Method | Path | Description |
|---|---|---|
GET |
/highlights |
List highlights |
GET |
/highlights/resolutions |
Resolution options |
GET |
/highlights/fps |
FPS options |
POST |
/highlights |
Generate highlight (auto) |
POST |
/highlights/by-ticks |
Generate by tick ranges |
POST |
/highlights/by-kill |
Generate by kill IDs |
GET /highlights
Query params:
demo_idstatus(NEW|PROCESSING|SUCCESS|FAILED)created_fromcreated_totype(auto|ticks|kill)limit(1..100)offset
curl -G "$BASE_URL/api/public/v1/highlights" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "type=auto" \
--data-urlencode "limit=20"
GET /highlights/resolutions
curl "$BASE_URL/api/public/v1/highlights/resolutions" \
-H "Authorization: Bearer $TOKEN"
Response shape:
{
"items": [
{"id": 1, "name": "1280x720", "width": 1280, "height": 720}
]
}
GET /highlights/fps
curl "$BASE_URL/api/public/v1/highlights/fps" \
-H "Authorization: Bearer $TOKEN"
Response shape:
{
"items": [
{"id": 1, "name": "60 FPS", "fps": 60}
]
}
POST /highlights
curl -X POST "$BASE_URL/api/public/v1/highlights" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"demo_id": 52,
"resolution_id": 1,
"fps_id": 1,
"title": "Mirage recap",
"use_transition": false,
"intro": "NONE"
}'
POST /highlights/by-ticks
curl -X POST "$BASE_URL/api/public/v1/highlights/by-ticks" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"demo_id": 52,
"ticks": [
{"start_tick": 15423, "end_tick": 15610},
{"start_tick": 30120, "end_tick": 30400}
],
"resolution_id": 1,
"fps_id": 1,
"title": "Round pivots"
}'
POST /highlights/by-kill
Accepts kill identifiers in these shapes:
demo_kill_ids: [1,2,3](recommended)kill_ids: [1,2,3](alias)demo_kill_id: 1(single-item alias)
curl -X POST "$BASE_URL/api/public/v1/highlights/by-kill" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"demo_id": 52,
"demo_kill_ids": [801, 805],
"pre_ticks": 192,
"post_ticks": 192,
"resolution_id": 1,
"fps_id": 1,
"title": "Entry chain"
}'
Response for generation endpoints (202):
{
"highlight_id": 311,
"status": "queued"
}
Error model
Standard errors:
401auth missing/invalid403revoked token or forbidden resource404resource missing422request validation/domain validation
Examples:
{"detail": "API token missing"}
{"detail": "API token revoked"}
{"detail": "Demo not found"}
{"detail": "Tick range is outside demo bounds"}
{
"detail": [
{
"loc": ["body", "resolution_id"],
"msg": "Field required",
"type": "missing"
}
]
}
Rate limits
No hard per-token rate-limiting policy is currently enforced by these routes.
Recommended client behavior:
- use retries with exponential backoff for
5xxand network errors - avoid aggressive polling (prefer webhooks where possible)
- use reasonable pagination (
limit <= 100) - deduplicate retries client-side by your own request IDs