AI PadelAPI documentation Back to site

Court server: computer vision

Rallies with ball trajectory, match summary, camera health and court bookings. Writes use the club token; reads accept the club token or a player token.

Base URL: https://your-server/api · Guide for this section: Court server and cloud

Rally #

POST/v1/cv/rally

Access: Club token Header X-Club-Token: <club token> — the club court server token.

A whole rally: timing, thinned ball trajectory in frame pixels, shots with speed, winning team. A repeat of the same rally_no overwrites the row — the court queue may resend after a connection drop.

Headers

NameTypeRequiredDescription
x-club-tokenstringyesCourt server club token

Request body application/json

FieldTypeRequiredDescription
match_idstring (uuid)yesmatchId
courtstringnoCourt name
rally_nointegeryesRally number — a repeat overwrites the row by it
min 0
t_startnumberyesStart, unix seconds
t_endnumberyesEnd, unix seconds
duration_snumbernoDuration, s; 0 — computed from t_start and t_end
default 0.0
patharray [array [number]]noThinned ball trajectory [x, y] in frame pixels, up to 400 points
items up to 400
path_fwintegernoTrajectory frame width
default 0
path_fhintegernoTrajectory frame height
default 0
shotsarray [object]noShots, up to 500
items up to 500
shots[].tnumberyesShot time, unix seconds
shots[].v_kmhnumbernoSpeed, km/h
default 0.0
shots[].xintegernox in frame pixels
default 0
shots[].yintegernoy in frame pixels
default 0
max_kmhnumbernoTop speed, km/h
default 0.0
avg_kmhnumbernoAverage speed, km/h
default 0.0
shots_countintegernoShot count; 0 — length of shots
default 0
winner_teamstring, or nullnoWinning team: A or B (1 and 2 are accepted too)

Example request

curl -X POST "https://your-server/api/v1/cv/rally" \
  -H "X-Club-Token: <club token>" \
  -H "Content-Type: application/json" \
  -d '{
  "match_id": "8c0f4a52-2d1e-4b7a-9f63-1a5e7d9b3c20",
  "court": "court4",
  "rally_no": 1,
  "t_start": 1759418000.0,
  "t_end": 1759418012.4,
  "duration_s": 12.4,
  "path": [[312, 401], [355, 380]],
  "path_fw": 1024,
  "path_fh": 768,
  "shots": [{"t": 1759418001.2, "v_kmh": 74.0, "x": 312, "y": 401}],
  "max_kmh": 96.0,
  "avg_kmh": 58.2,
  "shots_count": 7,
  "winner_team": "A"
}'

Responses

CodedetailMeaning
200—Success; example below
401bad_club_tokenInvalid club token
404match_not_foundMatch not found, belongs to another club, or you are not a participant
422[…]Parameter or body validation error: detail is a list of errors

Example response

{"ok": true, "rallyId": "1f7c2a90-3b4d-4e5f-8a6b-7c8d9e0f1a2b", "shots": 9}

Match summary #

POST/v1/cv/match-summary

Access: Club token Header X-Club-Token: <club token> — the club court server token.

Match summary: rally count, speeds, heat map and ball routes. A repeat updates the summary, no second map is created. If there are rallies and shots, the cloud fills the match average shots per rally.

Headers

NameTypeRequiredDescription
x-club-tokenstringyesCourt server club token

Request body application/json

FieldTypeRequiredDescription
match_idstring (uuid)yesmatchId
courtstringnoCourt name
ralliesintegernoRally count
default 0
max_kmhnumbernoTop speed, km/h
default 0.0
avg_kmhnumbernoAverage speed, km/h
default 0.0
total_shotsintegernoTotal shots
default 0
heatarray [array [number]]noHeat map: [x, y, n] — cell in frame pixels and count, up to 8000
items up to 8000
trailsarray [array [number]]noBall routes: [x1, y1, x2, y2, n] — cell-to-cell move and count, up to 4000
items up to 4000
fwintegernoFrame width
default 0
fhintegernoFrame height
default 0

Example request

curl -X POST "https://your-server/api/v1/cv/match-summary" \
  -H "X-Club-Token: <club token>" \
  -H "Content-Type: application/json" \
  -d '{
  "match_id": "8c0f4a52-2d1e-4b7a-9f63-1a5e7d9b3c20",
  "court": "court4",
  "rallies": 42,
  "max_kmh": 118.0,
  "avg_kmh": 61.5,
  "total_shots": 310,
  "heat": [[320, 240, 7]],
  "trails": [[320, 240, 360, 260, 3]],
  "fw": 1024,
  "fh": 768
}'

Responses

CodedetailMeaning
200—Success; example below
401bad_club_tokenInvalid club token
404match_not_foundMatch not found, belongs to another club, or you are not a participant
422[…]Parameter or body validation error: detail is a list of errors

Example response

{"ok": true, "heat": 120, "trails": 64}

Court health #

POST/v1/cv/health

Access: Club token Header X-Club-Token: <club token> — the club court server token.

Court health: cameras, software version, disk and GPU. The court server sends it every 10 seconds; only the latest state is kept. An unknown camera tag is not dropped but returned in unknown_tags. The response carries rally marks made by players in the app during the last 30 minutes (each is delivered once).

Headers

NameTypeRequiredDescription
x-club-tokenstringyesCourt server club token

Request body application/json

FieldTypeRequiredDescription
courtstringyesCourt name
tsnumbernoMeasurement time, unix seconds; 0 — cloud time
default 0.0
camerasarray [object]noCameras, up to 32
items up to 32
cameras[].tagstringyesCamera role — a tag from the agreed list (provided on connection)
cameras[].modelstringnoCamera model
cameras[].onlinebooleannoCamera online
default false
cameras[].fpsnumbernoFrames per second
default 0.0
cameras[].failsintegernoRead failures (cumulative)
default 0
cameras[].reopensintegernoReconnects (cumulative)
default 0
cameras[].last_frame_age_snumbernoAge of the last frame, s
default 0.0
cameras[].brightnumbernoFrame brightness
default 0.0
cameras[].temp_cnumber, or nullnoCamera temperature, °C, if known
cameras[].droppedintegernoDropped frames (cumulative)
default 0
cameras[].drop_rationumbernoDropped frame ratio
default 0.0
appobjectnoCourt server software
app.versionstringnoSoftware version
app.uptime_sintegernoUptime, s
default 0
hostobjectnoCourt server hardware
host.disk_free_gbnumber, or nullnoFree disk, GB
host.disk_used_pctnumber, or nullnoDisk used, %
host.gpu_temp_cnumber, or nullnoGPU temperature, °C
host.gpu_namestringnoGPU

Example request

curl -X POST "https://your-server/api/v1/cv/health" \
  -H "X-Club-Token: <club token>" \
  -H "Content-Type: application/json" \
  -d '{
  "court": "court4",
  "ts": 1759418400.0,
  "cameras": [{"tag": "<camera role tag>", "online": true, "fps": 25.0}],
  "app": {"version": "1.2137", "uptime_s": 86400},
  "host": {"disk_free_gb": 412.5, "gpu_temp_c": 61.0}
}'

Responses

CodedetailMeaning
200—Success; example below
401bad_club_tokenInvalid club token
422[…]Parameter or body validation error: detail is a list of errors

Example response

{
  "ok": true,
  "cameras": 4,
  "unknown_tags": [],
  "marks": [{"id": "0d4e8f21-6a3b-4c7d-9e1f-2a5b8c0d3e47", "ts": 1759418400.5, "source": "app"}]
}

Match computer vision data #

GET/v1/cv/match/{match_id}

Access: Club token or player token Either X-Club-Token: <club token> or Authorization: Bearer <player token>. If the club token is sent, it is the one checked.

Match rallies with trajectories and shots, plus the summary (heat map, routes) once the match is closed. With the club token only matches of that club are available.

Path parameters

NameTypeRequiredDescription
match_idstring (uuid)yesMatch id

Headers

NameTypeRequiredDescription
x-club-tokenstringnoCourt server club token

Example request

curl -X GET "https://your-server/api/v1/cv/match/8c0f4a52-2d1e-4b7a-9f63-1a5e7d9b3c20" \
  -H "X-Club-Token: <club token>"

Responses

CodedetailMeaning
200—Success; example below
401no_tokenNo token in the Authorization header
401invalid_tokenToken expired or invalid — refresh it via /v1/auth/refresh
401bad_club_tokenInvalid club token
404match_not_foundMatch not found, belongs to another club, or you are not a participant
422[…]Parameter or body validation error: detail is a list of errors

Example response

{
  "matchId": "8c0f4a52-2d1e-4b7a-9f63-1a5e7d9b3c20",
  "clubId": "c1",
  "court": "Court 4",
  "summary": {
    "rallies": 42,
    "maxKmh": 118.0,
    "avgKmh": 61.5,
    "totalShots": 310,
    "heat": [[320, 240, 7]],
    "trails": [[320, 240, 360, 260, 3]],
    "fw": 1024,
    "fh": 768
  },
  "rallies": [
    {
      "no": 1,
      "tStart": 1759418000.0,
      "tEnd": 1759418012.4,
      "durationS": 12.4,
      "maxKmh": 96.0,
      "avgKmh": 58.2,
      "shotsCount": 7,
      "winnerTeam": "A",
      "path": [[312, 401], [355, 380]],
      "pathFw": 1024,
      "pathFh": 768,
      "shots": [{"t": 1759418001.2, "vKmh": 74.0, "x": 312, "y": 401}]
    }
  ]
}

Latest court health #

GET/v1/cv/court/{court}/health

Access: Club token or player token Either X-Club-Token: <club token> or Authorization: Bearer <player token>. If the club token is sent, it is the one checked.

The latest court state and its age in seconds (ageS). With the club token — a court of that club; with a player token pass club_id.

Path parameters

NameTypeRequiredDescription
courtstringyesCourt name as on the court server

Query parameters

NameTypeRequiredDescription
club_idstringnoClub id

Headers

NameTypeRequiredDescription
x-club-tokenstringnoCourt server club token

Example request

curl -X GET "https://your-server/api/v1/cv/court/court4/health?club_id=c1" \
  -H "X-Club-Token: <club token>"

Responses

CodedetailMeaning
200—Success; example below
401no_tokenNo token in the Authorization header
401invalid_tokenToken expired or invalid — refresh it via /v1/auth/refresh
401bad_club_tokenInvalid club token
400club_id_requiredclub_id is required with a player token
404court_health_not_foundNo health data from this court yet
422[…]Parameter or body validation error: detail is a list of errors

Example response

{
  "clubId": "c1",
  "court": "Court 4",
  "ts": 1759418400.0,
  "ageS": 4.2,
  "cameras": [
    {
      "tag": "<camera role tag>",
      "model": "",
      "online": true,
      "fps": 25.0,
      "fails": 0,
      "reopens": 0,
      "last_frame_age_s": 0.1,
      "bright": 0.0,
      "temp_c": null,
      "dropped": 0,
      "drop_ratio": 0.0
    }
  ],
  "app": {"version": "1.2137", "uptime_s": 86400}
}

Court bookings now #

GET/v1/cv/court-bookings

Access: Club token Header X-Club-Token: <club token> — the club court server token.

Bookings on the club courts: the current one and those within the next three hours, with the line-up (no phone numbers). Courts are passed as a repeated court parameter (up to 16) with names as on the court server; without it — all club courts. A court unknown to the cloud comes back with known=false. Cancelled bookings are not returned.

Query parameters

NameTypeRequiredDescription
courtarray [string]noCourt name as on the court server
items up to 16

Headers

NameTypeRequiredDescription
x-club-tokenstringyesCourt server club token

Example request

curl -X GET "https://your-server/api/v1/cv/court-bookings?court=court4" \
  -H "X-Club-Token: <club token>"

Responses

CodedetailMeaning
200—Success; example below
401bad_club_tokenInvalid club token
422[…]Parameter or body validation error: detail is a list of errors

Example response

{
  "clubId": "c1",
  "now": "2026-10-02 18:05",
  "courts": {
    "court4": {
      "known": true,
      "current": {
        "id": "b71c2e94-0a3f-4d58-8e26-9f1d3c5a7b40",
        "court": "Court 4",
        "day": "2026-10-02",
        "start": "18:00",
        "end": "19:30",
        "durationMin": 90,
        "current": true,
        "players": [
          {
            "user_id": "3d6e9a10-5b2c-4f8e-a1d7-6c4b2e0f9a83",
            "name": "Ivan Petrov",
            "short": "Ivan P.",
            "booker": true
          }
        ]
      },
      "upcoming": []
    }
  }
}