Local court server API
Game data stays at the club: match summaries, ball measurements, moments and video live on the court server in the club network and are served from there, with no internet needed. The cloud is for what is shared between clubs and the player app: bookings, wallet, rating.
Where to get what
| Data | Source | Access |
|---|---|---|
| Match summary: score, line-up, player movement, highlights | Court server, /match/summary | Integration key |
| Player analysis: shots, technique, level | Court server, /match/report | Integration key |
| Ball measurements: rallies, speeds, bounces, heatmaps | Court server, /measure/* | Integration key |
| Video: moments, highlights, replays, full match recordings | Court server, /archive/* | Integration key |
| Court, recording and session state | Court server, /status, /board.json, /session/… | Integration key |
| Live score and on-air status | Court server, /live.json, /live/…/state.json | No key |
| Bookings, slots, wallet, player rating, player profile | Cloud, see the API reference | Cloud tokens |
The court server sends only match results, aggregated stats and clips for the player app to the cloud (see Court server and cloud). Full recordings, moments from every camera and raw ball measurements stay at the club and are available only locally.
Address
http://<court server address>:8016- The court server is reachable in the club network. The club receives its address at setup; the default port is 8016.
- A court is referenced by its name as configured on the court server, URL-encoded (for example
Court%201). The list of names is in thecourt_namesfield of/status. - Responses are UTF-8 JSON. Some responses are the same structures the court screen and the club video wall use, so they include display fields (captions, thumbnail links). Court names, captions and player names come in the language the club set them in.
Integration key
The club system (accounting, CRM, video storage) sends the key in the X-Integration-Key header. The key opens read-only access to the game data listed below. It cannot control the court: score, line-up, sessions, service restarts, camera settings, live video and audio stay behind the staff PIN.
curl "http://<court server address>:8016/status" \
-H "X-Integration-Key: <integration key>"- One key per system: your accounting system and your CRM get separate keys, and either can be revoked without touching the other. The key is created on the court server and shown once; this documentation uses the placeholder
<integration key>. - To get one, contact your platform administrator with the club name and the system that needs access. New and revoked keys take effect after the court server services restart, which is done when no game is in progress.
- A wrong key, a path outside the list and any request other than
GETreturn401 bad_pin.
Match summaries and analyses contain player personal data: names and the last four digits of the phone number. Keep the key on your system's server, not in web pages or apps, and do not pass the data outside the club without the players' consent.
Methods
| Method | Parameters | Returns |
|---|---|---|
GET /match/summary | court | Latest match summary on the court: time, duration, set scores, winner, players with movement (distance, work rate, top speed, sprints, zones), teams, highlights and the match recording. No summary: 404 no_summary |
GET /match/report | court, t0 (optional, match start from the summary) | Player analysis: shots by type, technique score, level, mistakes and plan, episodes. Field status: ready, pending (still processing), failed, missing, offline (no cloud link, cached copy served), unavailable (not in the license) |
GET /measure/totals | court | Court measurement totals: rallies, playing time, top and average ball speed, number of measurements behind each value |
GET /measure/history | court, limit (50), match_ref | Rallies: duration, speeds |
GET /measure/rally/{rally_id} | none | Rally summary |
GET /measure/trajectory/{rally_id} | limit (20000), measured_only | Ball trajectory; reconstructed points are flagged interpolated |
GET /measure/events | court, rally_id, kind, limit (500) | Ball events: bounces, shots, glass hits, with speed and its error margin |
GET /measure/heatmap | court, kind (bounce), nx (20), ny (10), match_ref | Event heatmap over court cells with the average speed per cell |
GET /measure/daemon | none | Whether the measurement service is running and keeping up with the cameras |
GET /archive/list.json | court, kind (moment, highlight, episode, match), days (7, max 90) | Video on the court server disk by day, newest first: per-camera files, duration, size, readiness; match summaries for the same days. Up to 1500 entries, then truncated: true |
GET /archive/file | root, path from the list; download=1 to save as a file | MP4 video or JPEG thumbnail. Supports seeking: Range header, 206 response |
GET /moments | court | Match moments marked by players or automatically: time, caption, camera angles |
GET /episodes/{court} | limit (12) | Latest points with the system decision and its reason |
GET /positions | court | Where the players and the ball are on the court plan right now |
GET /ball/live | court (optional) | Where the ball is right now and how telemetry intake is going |
GET /session/{court} | none | Current court session: opened and until times, format, line-up, booking, score of the match in progress. No session: 404 no_session_on_court |
GET /americano/{court} | none | Americano game on the court and its score |
GET /board.json | none | Club board: all courts, sessions, scores, cameras; server disk and GPU |
GET /status | none | Court names, license, cloud link and upload queue |
GET /rec/status | none | Recording per camera, retention in hours, disk used |
Open without a key: GET /health (server alive, how many courts are playing), GET /live.json (which courts are on air) and GET /live/{court}/state.json (on-air flag and score). They contain nothing beyond what the scoreboard shows.
Field names in /measure/* responses are currently in Russian; an English field map is available on request. If the database flag in these responses is false, the measurement database is unavailable, and an empty answer does not mean there were no rallies.
After a match: summary and video
S="http://<court server address>:8016"
K="X-Integration-Key: <integration key>"
C="Court%201"
# 1. Latest match summary on the court
curl -H "$K" "$S/match/summary?court=$C"
# → {"court": "Court 1", "t0": 1790863200, "day": "2026-10-02", "time_from": "18:00", "time_to": "19:28",
# "sets": [{"team1": 6, "team2": 4, "unfinished": false}, …], "winner": 1,
# "players": [{"name": "Alex", "team": 1, "phone_tail": "0001", "distance_m": 2350.4,
# "top_speed_ms": 6.1, "sprints": 14, …}, …],
# "highlights": [{"title": "…", "duration_s": 18, "ready": true, "url": "…"}],
# "match_video": {"duration_s": 5280, "ready": true, "url": "…"}, …}
# 2. Player analysis for that match (t0 from the summary)
curl -H "$K" "$S/match/report?court=$C&t0=1790863200"
# 3. Today's video: full match recordings only
curl -H "$K" "$S/archive/list.json?court=$C&kind=match&days=1"
# → {"items": [{"id": "…", "kind": "match", "day": "2026-10-02", "time": "18:00", "duration_s": 5280,
# "cams": [{"cam": "hik101", "root": "rec", "path": "…", "size": 1834221568,
# "ready": true, …}], …}], "summaries": […], "truncated": false}
# 4. Download a camera file (root and path from the list, path URL-encoded)
curl -H "$K" -o match.mp4 "$S/archive/file?root=<root>&path=<path>&download=1"- Collect video while it is on disk: recordings are kept for the number of hours in
retention_hof/rec/status(72 by default) and then deleted. - A file with
ready: falseis still being written; fetch it later. - The summary endpoint returns the latest match on the court. To miss nothing, poll
/archive/list.json: itssummariesfield has every match summary for the selected days.
Errors
401 bad_pin: no key, a wrong key, or the method is not in the key's read list.400 unknown_court: no such court on the server;422: a required parameter is missing (usuallycourt).404: no summary (no_summary), session (no_session_on_court) or file (not_found).