Skip to the article
Aniq-UI

KinoraDevices and ingest keys

Devices and ingest keys

How a member's watch, phone or a device aggregator writes steps, heart rate and workouts into Kinora with a personal key.

For the Full Stack package

How data gets in

Kinora does not pull from Garmin, Fitbit, Apple Health or any other service. Data arrives because something sends it: a member's own key lets a device, an app or a device aggregator write that member's movement figures and workouts through one door, /api/ingest.

  • Aggregators such as Terra, Rook and Spike link a member's watch account once, then send its data to an address you give them. A small adapter of your own maps their payload onto the shape below and forwards it with that member's key.
  • The adapter is not in the template: it is the one part that depends on which provider you choose.

In the dashboard

  • In Settings, the Connected Devices card lists the device catalogue, each one connected or not, with its last sync and battery. The seed ships a GPS sports watch, the Kinora Band Pro and a smart body scale.
  • Connect a data source creates a key: the member names it, and the full key is shown once, to copy. After that only its first 12 characters are shown.
  • A key can be revoked at any time, and stops working at once.

The keys

  • A key names exactly one account. It writes that account's movement figures and sessions and nothing else.
  • Creating one needs fitness.edit, which only the Member role holds: a staff token answers 403.
  • A key is kin_ followed by 64 hexadecimal characters. The server keeps only its SHA-256 hash and its first 12 characters, so a leaked database does not hand anyone a working key.
MethodPathPermissionWhat it does
GET/api/fitness/devices/keysfitness.viewThe account's keys that are not revoked, newest first
POST/api/fitness/devices/keysfitness.editCreates one ({ name }, 1 to 80 characters) and answers with the full key, readable this once
DELETE/api/fitness/devices/keys/:idfitness.editRevokes one; 404 api_key_not_found for a key that is not the account's
GET/api/fitness/devicesfitness.viewThe device catalogue with the account's connection to each
POST/api/fitness/devices/:key/togglefitness.editConnects or disconnects a device
POST/api/fitness/devices/:key/syncfitness.editAlways 400 device_sync_unavailable: the server pulls nothing

Sending data

Every /api/ingest route reads the key from the X-Api-Key header and nothing else; a bearer token is not accepted there. A missing key answers 401 api_key_missing, an unknown or revoked one 401 api_key_invalid.

  1. Check the key

    Terminal
    curl http://localhost:8000/api/ingest/whoami -H "X-Api-Key: kin_…"

    Expected result: It answers with the account id and the key's name.

  2. Send a day's figures

    POST /api/ingest/daily-metrics with a list of days. Only date is required; a figure you leave out keeps its value, so a heart-rate strap and a step counter can report the same day without erasing each other. Sending a date again corrects that day.

    Body
    {
      "days": [
        { "date": "2026-08-23", "steps": 15342, "distanceKm": 11.4, "activeKcal": 941, "totalKcal": 2680,
          "floorsClimbed": 14, "exerciseMinutes": 78, "activeMinutes": 96, "standHours": 11,
          "restingHr": 58, "avgHr": 74 }
      ]
    }

    Expected result: { "written": 1 }. A value out of range (a negative figure, standHours over 24, a heart rate outside 20 to 250) answers 400.

  3. Send workouts

    POST /api/ingest/sessions with a list of sessions. workoutSlug must name a workout in the catalogue (404 workout_not_found otherwise). A session is known by its account, workout and start, so sending it again does not count it twice. Every session sent is marked done.

    Body
    {
      "sessions": [
        { "workoutSlug": "conditioning", "startedAt": "2026-08-23T07:12:00.000Z",
          "finishedAt": "2026-08-23T07:49:00.000Z", "minutes": 37, "kcal": 412 }
      ]
    }

Each day written records the key's name as its source, which keeps a synced day apart from one entered by hand. Each accepted request stamps the key's last use.

Stuck on a step?

Find a fix before you start over.

Troubleshooting

Cookie Preferences

We use cookies to enhance your browsing experience, analyze site traffic, and personalize content. By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising.