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: queued for newly created demo; otherwise existing demo status (new|processing|success|failed)
  • was_already_processed_successfully: true when this upload matched an existing demo that was already in SUCCESS
  • user_demo_assignment: newly_assigned when this call created the user<->demo link, already_assigned when link already existed

GET /demos

Query params:

  • created_from (ISO datetime)
  • created_to (ISO datetime)
  • map
  • status (NEW|PROCESSING|SUCCESS|FAILED)
  • upload_type (MANUAL|API)
  • search
  • limit (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:

  • round
  • attacker_steam_id (SteamID64 string)
  • victim_steam_id (SteamID64 string)
  • limit (1..500)
  • offset

Response note:

  • attacker_steam_id and victim_steam_id are 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_id
  • status (NEW|PROCESSING|SUCCESS|FAILED)
  • created_from
  • created_to
  • type (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:

  • 401 auth missing/invalid
  • 403 revoked token or forbidden resource
  • 404 resource missing
  • 422 request 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 5xx and network errors
  • avoid aggressive polling (prefer webhooks where possible)
  • use reasonable pagination (limit <= 100)
  • deduplicate retries client-side by your own request IDs