Skip to main content

Documentation Index

Fetch the complete documentation index at: https://dev.1st.app/llms.txt

Use this file to discover all available pages before exploring further.

What’s going on

When you ask the API for “all my devices” or “all readings in May”, the response only includes the first 1000 results. If you have more than that, you need to ask again to get the next batch. This page is how. If you have fewer than 1000 devices on your team (most clubs do), you’ll never hit this. You can ignore this page until you do.

How it works

When the response has more results waiting, you’ll see a next_cursor value at the end:
{
  "data": [ /* first 1000 results */ ],
  "next_cursor": "eyJ0ZWFtX2lkIjoiYWJjZCIsImxhc3RfaWQiOiJlZmdoIn0="
}
Think of next_cursor like a bookmark. It saves your place. On your next call, send it back as ?cursor=... and you’ll get the next batch:
GET /v1/devices?cursor=eyJ0ZWFtX2lkIjoiYWJjZCIsImxhc3RfaWQiOiJlZmdoIn0=
When next_cursor comes back as null, you’ve got everything.

What the loop looks like

If you’re asking an AI to write your integration, just say “walk the pagination”. Here’s what it’ll write in Python:
import os, requests

API_KEY = os.environ["ST_API_KEY"]
URL = "https://api.1st.app/v1/devices"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

all_devices = []
cursor = None

while True:
    params = {"cursor": cursor} if cursor else {}
    r = requests.get(URL, params=params, headers=HEADERS)
    r.raise_for_status()
    page = r.json()
    all_devices.extend(page["data"])
    cursor = page["next_cursor"]
    if cursor is None:
        break

print(f"Got {len(all_devices)} devices total")
Or in Google Apps Script:
const KEY = PropertiesService.getScriptProperties().getProperty('ST_API_KEY');
let all = [], cursor = null;
do {
  const url = 'https://api.1st.app/v1/devices' +
    (cursor ? '?cursor=' + encodeURIComponent(cursor) : '');
  const page = JSON.parse(
    UrlFetchApp.fetch(url, { headers: { Authorization: 'Bearer ' + KEY } })
      .getContentText()
  );
  all = all.concat(page.data);
  cursor = page.next_cursor;
} while (cursor);

A few things to know

Don’t try to read the next_cursor value. It’s a random-looking string of letters and numbers. The format is meant for the API to read, not you. Just save it and send it back on the next call. Cursors are tied to your API key. If you save a cursor from one key and try to use it with a different key, you’ll get a cursor_team_mismatch error. Drop the cursor and start over. You can’t skip ahead. There’s no “give me page 5”. You have to walk through every page from the beginning until you reach the one you want. Don’t save cursors for later. They expire after a while. If your script saves a cursor at noon and tries to use it the next morning, it might come back as cursor_invalid. Walk through all your pages in one run.

When cursors break

ErrorWhat happenedFix
cursor_invalidThe cursor is too old, or got corrupted somewhere.Start the loop again from the beginning (no ?cursor= on the first call).
cursor_team_mismatchThe cursor came from a different API key.Make sure your cursor and your Authorization header are from the same key.