Join the FFS Discord? — server startup, voice comms and event announcements Join →

DCS World Dedicated Server Community

Owner's Health

loading...

Public API

The heart-rate data shown on this page is also published as an unauthenticated, read-only API. CORS is enabled, so you can fetch it directly from the browser.

Base URL https://freedomflight.jp/health/v2/api/public

What the API returns right now

Loading
GET /latest?type=heart-rate

Endpoints

Method / PathDescription
GET /types List of published data types and their limits, so clients don't have to hardcode them.
GET /latest?type=heart-rate The latest single sample, with an age_seconds field.
GET /series?type=heart-rate&minutes=60 Time series. By default it returns the recorded granularity without decimation.

/series parameters

NameDefaultDescription
typeheart-rate Data type. Unknown / unpublished types return 404.
minutes60 How many minutes back from the end. Max 1440 (24 h); anything larger returns 400.
endnow End timestamp (ISO 8601). Use it to slice a window in the past.
max_points50000 When set, the series is decimated to evenly spaced points. Check truncated to see whether decimation happened.

Response example

$ curl -s 'https://freedomflight.jp/health/v2/api/public/latest?type=heart-rate'
{
  "data_type": "heart-rate",
  "label": "心拍数",
  "unit": "bpm",
  "value": 66.0,
  "time": "2026-08-27T03:59:43Z",   // UTC
  "age_seconds": 465                // seconds since the sample was taken
}

$ curl -s 'https://freedomflight.jp/health/v2/api/public/series?type=heart-rate&minutes=60'
{
  "data_type": "heart-rate",
  "label": "心拍数",
  "unit": "bpm",
  "start": "2026-08-27T03:07:28Z",
  "end":   "2026-08-27T04:07:28Z",
  "count": 1433,
  "truncated": false,               // true = decimated by max_points
  "points": [
    { "t": "2026-08-27T03:07:30Z", "v": 61.0 },
    { "t": "2026-08-27T03:07:33Z", "v": 62.0 },
    ...
  ]
}

Resolution and freshness

Data is stored at the granularity recorded by the Fitbit Charge 6, so heart rate can be retrieved at a median interval of 2–3 seconds (roughly 36,000 points per day).

However, it is not real-time. The watch syncs via the phone to Google's cloud, so even the newest point is typically several to a dozen-plus minutes old. When the watch is away from the phone (e.g. while sleeping) gaps of several hours can occur. This lag comes from the data provider and cannot be shortened on our side.

For that reason, short windows like minutes=5 can legitimately return count = 0. If you need "the current value", use /latest and judge staleness from age_seconds. minutes of 30 or more is recommended.

Limits

Usage examples

// Browser (CORS enabled)
const r = await fetch(
  'https://freedomflight.jp/health/v2/api/public/series?type=heart-rate&minutes=60');
const { points, unit } = await r.json();
console.log(points.length, unit);   // 1433 'bpm'
# Python
import urllib.request, json
BASE = "https://freedomflight.jp/health/v2/api/public"

with urllib.request.urlopen(f"{BASE}/latest?type=heart-rate") as r:
    d = json.load(r)
print(f"{d['value']:.0f} {d['unit']} ({d['age_seconds'] // 60} min ago)")

# Last 6 hours decimated to 5-minute granularity
url = f"{BASE}/series?type=heart-rate&minutes=360&max_points=72"
with urllib.request.urlopen(url) as r:
    s = json.load(r)
print(s["count"], "points", "decimated" if s["truncated"] else "as recorded")

Implementation: GoogleHealthCollector (collects and stores 42 data types from Google Health API v4). It is a separate pipeline from the heart-rate panel on this page; only heart rate from it is published.