SkyTrackPro API v1 – Developer Guide

This document describes how to authenticate and use the SkyTrackPro API for login, IGC upload, live tracking, and task access.

v1
Base URL for all endpoints:
https://skytrackpro.ch/api/v1/...
For example: GET /api/v1/auth/me, POST /api/v1/flights/upload, etc.

1. Introduction

The SkyTrackPro API allows trusted clients (mobile apps, companion tools, integrations) to:

  • Log users in and retrieve basic user info
  • Upload and analyze IGC flight files
  • Start and stop live tracking sessions and push live positions
  • Query active live users / sessions for map display
  • Fetch competition / task definitions

Every API call requires:

  • A valid API client key (via X-Api-Key header or ?api_key=... query parameter)
  • For user-specific actions, a valid short-lived access token (via Authorization: Bearer ...) or an existing JScms session (browser).

2. API Client Keys

Each external application is identified by an entry in jscms_skytrack_api_clients. An API key is a 64-character string stored in the api_key column and must be sent with every request.

Header usage
GET /api/v1/auth/me HTTP/1.1
Host: skytrackpro.ch
X-Api-Key: <YOUR_CLIENT_API_KEY>
Authorization: Bearer <USER_ACCESS_TOKEN>
Query parameter (fallback)
GET /api/v1/auth/me?api_key=<YOUR_CLIENT_API_KEY> HTTP/1.1
Host: skytrackpro.ch
Authorization: Bearer <USER_ACCESS_TOKEN>
Important: If the API key is missing, invalid, suspended, or revoked, the API responds with 401 Unauthorized and { "ok": false, "message": "Missing/Invalid API key" }.

3. User Authentication

User authentication uses the existing JScms login system and issues opaque access tokens (short-lived) and refresh tokens (long-lived) for API calls. There are two ways to be "logged in":

  1. Via a Bearer access token issued by /api/v1/auth/login or /api/v1/auth/refresh
  2. Via an existing JScms browser session and cookies
Token lifetimes (default):
  • Access token: valid for about 1 day (short-lived)
  • Refresh token: valid for a longer period (e.g. 90 days)
Your app should store both tokens securely and use the refresh token to obtain new access tokens without asking for the user's password again.

3.1 Login – POST /api/v1/auth/login

Endpoint: https://skytrackpro.ch/api/v1/auth/login

Request body (JSON):

{
  "email": "pilot@example.com",
  "password": "secret-password",
  "remember": true
}

Example curl:

curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  -d '{"email":"pilot@example.com","password":"secret","remember":true}' \
  "https://skytrackpro.ch/api/v1/auth/login"

Successful response:

{
  "ok": true,
  "token": "64-char-hex-access-token",
  "refresh_token": "64-char-hex-refresh-token",
  "user": {
    "id": 123,
    "email": "pilot@example.com"
  }
}
Use the returned token (access token) in the Authorization: Bearer ... header for all user-level endpoints (flights upload, live start/stop/tick, etc.). Store the refresh_token securely on the device and use it to obtain new access tokens via POST /api/v1/auth/refresh.

3.2 Current user – GET /api/v1/auth/me

Endpoint: https://skytrackpro.ch/api/v1/auth/me

Example:

curl \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  -H "Authorization: Bearer <USER_ACCESS_TOKEN>" \
  "https://skytrackpro.ch/api/v1/auth/me"

Sample response:

{
  "ok": true,
  "user": {
    "id": 123,
    "email": "pilot@example.com",
    "name": "Pilot Name",
    "usergroupid": 5,
    "access": 1,
    "public": 1
  }
}

3.3 Refresh access token – POST /api/v1/auth/refresh

Endpoint: https://skytrackpro.ch/api/v1/auth/refresh

Use this endpoint when the access token has expired. The user does not need to re-enter their email and password, as long as the refresh token is still valid.

Request body (JSON):

{
  "refresh_token": "64-char-hex-refresh-token"
}

Example curl:

curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  -d '{"refresh_token":"64-char-hex-refresh-token"}' \
  "https://skytrackpro.ch/api/v1/auth/refresh"

Successful response:

{
  "ok": true,
  "token": "new-64-char-hex-access-token",
  "refresh_token": "64-char-hex-refresh-token",
  "user": {
    "id": 123,
    "email": "pilot@example.com",
    "name": "Pilot Name",
    "usergroupid": 5,
    "access": 1,
    "public": 1
  }
}
Client behaviour:
  • Store both token (access) and refresh_token.
  • When an API call returns 401 due to an expired access token, call /api/v1/auth/refresh with the refresh token.
  • Only prompt the user to log in again when the refresh token is expired or invalid.

4. Flights – IGC Upload

Upload an IGC file, analyze it, and create a SkyTrack flight entry. The user must have permission to manage tracks.

Requirements:
  • Valid API key
  • Valid user access token (Bearer)
  • User must pass canManageTracks()
  • User must confirm rights / airspace responsibility (agree/st_agree = 1)
4.1 Endpoint – POST /api/v1/flights/upload

Endpoint: https://skytrackpro.ch/api/v1/flights/upload

A) Multipart upload (recommended for browsers)

Form fields:

  • file – IGC file (required)
  • title – optional title
  • is_public0/1 (fallback for visibility)
  • visibilityprivate|org|public|unlisted
  • org_id – optional organization id
  • st_agree / agree – must be 1
curl -X POST \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  -H "Authorization: Bearer <USER_ACCESS_TOKEN>" \
  -F "file=@/path/to/flight.igc" \
  -F "title=Evening soaring flight" \
  -F "visibility=public" \
  -F "st_agree=1" \
  "https://skytrackpro.ch/api/v1/flights/upload"
B) JSON upload (base64)

JSON body:

{
  "file_base64": "<base64 of IGC>",
  "file_name": "flight.igc",
  "title": "XC Flight",
  "visibility": "public",
  "org_id": 5,
  "agree": 1
}
Sample response
{
  "ok": true,
  "message": "IGC uploaded and analyzed.",
  "track_id": 987,
  "duplicate": false,
  "date": "2025-06-13",
  "year": 2025,
  "visibility": "public",
  "late_upload": false,
  "notices": [],
  "meta": {
    "...": "full analysis / stats / compliance data"
  }
}

5. Live Tracking

Live tracking uses a separate database and two main tables: jscms_skytrack_live_sessions and jscms_skytrack_live_points. The API separates pilot-side actions (start/stop/tick) from viewer-side actions (sessions/users/track/tail).

Body:

{
  "task_id": 123,          // optional
  "org_id": 5,             // optional
  "mode": "freeflight",    // e.g. "freeflight", "task"
  "device_label": "Phone"
}

Example:

curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  -H "Authorization: Bearer <USER_ACCESS_TOKEN>" \
  -d '{"task_id":123,"mode":"freeflight","device_label":"Phone"}' \
  "https://skytrackpro.ch/api/v1/live/start"

Response:

{
  "ok": true,
  "session_id": 456
}

Body:

{
  "session_id": 456
}

Example:

curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  -H "Authorization: Bearer <USER_ACCESS_TOKEN>" \
  -d '{"session_id":456}' \
  "https://skytrackpro.ch/api/v1/live/stop"

Body:

{
  "session_id": 456,
  "points": [
    {
      "ts": 1730784300,
      "lat": 46.123456,
      "lon": 7.123456,
      "alt": 1500,
      "alt_bar": 1490,
      "speed": 11.2,
      "climb": 0.8,
      "heading": 230
    }
  ]
}

Example:

curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  -H "Authorization: Bearer <USER_ACCESS_TOKEN>" \
  -d '{"session_id":456,"points":[{"ts":1730784300,"lat":46.1,"lon":7.1,"alt":1500}]}' \
  "https://skytrackpro.ch/api/v1/live/tick"

Response:

{
  "ok": true,
  "stored": 1
}

Query parameters:

  • org_id – optional
  • task_id – optional
curl \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  "https://skytrackpro.ch/api/v1/live/sessions?org_id=5"

Response includes a list of active sessions (no points).

Query parameters:

  • limit – default 500, max 5000
  • since_ts – optional, only points after this UNIX ts
curl \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  "https://skytrackpro.ch/api/v1/live/session/456/track?limit=500"

Response contains ordered points ready for plotting on a map.

Retrieve only the most recent point of the session.

curl \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  "https://skytrackpro.ch/api/v1/live/session/456/tail"

Perfect for ultra-light marker updates on the live map.

Query parameters:

  • org_id – optional
  • task_id – optional
  • mode – optional (e.g. freeflight)
  • since_ts – optional, filter for recent points
  • public_only0|1, hide non-public users if 1
  • limit – default 200, max 1000 sessions
curl \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  "https://skytrackpro.ch/api/v1/live/users?public_only=1"

Response: markers[] with session, last point, and basic user info – ideal for a live radar / map overview.

6. Tasks

6.1 List tasks – GET /api/v1/tasks

Endpoint: https://skytrackpro.ch/api/v1/tasks

Query parameters:

  • org_id – filter by organization
  • category_id – filter by category
  • published0 or 1
curl \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  "https://skytrackpro.ch/api/v1/tasks?org_id=5&published=1"
6.2 Get task details – GET /api/v1/tasks/{id}

Endpoint: https://skytrackpro.ch/api/v1/tasks/123

Returns full task metadata, including current version, distances, and the parsed spec and calc JSON for turnpoints and geometry.

curl \
  -H "X-Api-Key: <YOUR_CLIENT_API_KEY>" \
  "https://skytrackpro.ch/api/v1/tasks/123"

Quick start for mobile / companion apps

Typical flow for a SkyTrackPro client app that talks to the API:

  1. Get an API client key
    Register and/or login with your account. Go to your profile -> flight profile and generate your api_key. Your app must send this key with every request via the X-Api-Key header.
  2. Log the user in once
    Call POST /api/v1/auth/login with the pilot’s email and password. Store the returned:
    • token – short-lived access token
    • refresh_token – long-lived refresh token
    Never store the user’s password after login.
  3. Call API endpoints with the access token
    For user-specific endpoints (upload IGC, live start/stop/tick, etc.) send:
    • X-Api-Key: <YOUR_CLIENT_API_KEY>
    • Authorization: Bearer <ACCESS_TOKEN>
  4. Handle expired access tokens via refresh
    If a request fails with 401 due to an expired token:
    1. Call POST /api/v1/auth/refresh with refresh_token.
    2. Update your stored token with the new value.
    3. Retry the original API call.
    Only if the refresh also fails (e.g. invalid/expired) do you ask the user to log in again via /auth/login.
  5. Logout / reset app
    To log the user out of your app, simply delete the stored token and refresh_token and send no more authenticated requests until they log in again.
Minimal pseudo-code
// 1) Login
POST /api/v1/auth/login
  { email, password } → { token, refresh_token }

// 2) Store tokens securely
accessToken = token
refreshToken = refresh_token

// 3) Call protected endpoint
GET /api/v1/auth/me
  Headers:
    X-Api-Key: <client key>
    Authorization: Bearer <accessToken>

// 4) On 401 due to expiry:
POST /api/v1/auth/refresh
  { refresh_token: refreshToken } → { token: newAccessToken }

accessToken = newAccessToken
retry original request

Need more endpoints or custom integrations? Contact the SkyTrackPro administrator to register a new API client and discuss your use case.