Documentation

Keely for developers

Changes

The rows that changed since a time, in your scopes, for an app that keeps a copy and catches up.

Updated

On this page
  1. GET /v1/changes

An app that keeps a copy of a person’s data polls GET /v1/changes?since=<time> and fetches what changed, or subscribes to events and is told. A morning’s numbers arrive when the person’s iPhone syncs the band and backs the night up, which is usually once in the morning and then as the day goes on; once an hour is plenty, and once a day is enough for most apps.

GET /v1/changes

Scope
any; only the kinds your scopes cover are listed
Query
since, a UTC time, at most 90 days back; limit, up to 500
  • kind is night, day, workout, journal_tag or journal_entry, and key the date, the workout’s id, the tag’s key or the entry’s id. Only the kinds your scopes cover are listed: nights need nights, days days, workouts workouts, and the journal’s rows journal.
  • Order and paging. Changes come ordered by updated_at, then key, at most 500 at a time (limit, up to 500). When has_more is true, call again with since=next. next is the newest updated_at seen, or your since when nothing changed.
  • Overlap and dedupe. A row can be written in the second you read, so on each poll start 5 minutes before the next you stored, as the Keely app does, and dedupe by kind and key. Reading a row twice is harmless; a night, a day or a workout is replaced whole when it changes.
  • Removals. A workout the person removed comes with "removed": true: delete your copy. A night or a day that no longer exists simply stops being listed; fetching it answers 404.
  • The floor. since can be at most 90 days back. For the first fill, read the days you need with GET /v1/days?from&to, then poll from the time you started.

/v1/changes and /v1/events answer different questions: changes are rows by their updated_at, at any age, for catching up; events are typed, buffered and kept 30 days, for reacting.

Request
curl "https://meetkeely.com/api/v1/changes?since=2026-09-27T06:00:00Z" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Response
{
  "since": "2026-09-27T06:00:00Z",
  "next": "2026-09-27T15:20:00Z",
  "has_more": false,
  "changes": [
    { "kind": "night", "key": "2026-09-27", "date": "2026-09-27", "updated_at": "2026-09-27T06:30:00Z" },
    { "kind": "workout", "key": "5f3c0e1d2b4a6978", "date": "2026-09-27", "updated_at": "2026-09-27T15:20:00Z" },
    { "kind": "day", "key": "2026-09-27", "date": "2026-09-27", "updated_at": "2026-09-27T15:20:00Z" }
  ]
}