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.

When a device moves between athletes or rooms, you don’t want last month’s data to mix with this month’s. The 1st API ties each block of usage to an assignment, and you can ask for just the readings from one block via ?assignment_id=.

The shape of an assignment

An assignment is one continuous block of “this device was tracking this athlete (or this room) from this date to that date.” It has:
  • assignment_id — the ID you’ll pass on the readings endpoint
  • typeathlete or place
  • label — the player’s name or the room’s name
  • home_or_travel — where the device was set up during the block
  • started_at — when the block began
  • ended_at — when the block closed, or null if it’s still open
The currently-open assignment also shows up inline on every device, as the active_assignment field of GET /v1/devices/{id}. Past assignments are listed on GET /v1/devices/{id}/assignments, newest-first.

The hero query

You want last month’s CO2 readings for L. Marchetti’s pre-season recovery block, even though the device has since moved to a room.

Step 1: get the assignment_id

curl -H "Authorization: Bearer $ST_API_KEY" \
  "https://api.1st.app/v1/devices/<device_id>/assignments"
{
  "data": [
    {
      "assignment_id": "f4e9b8d2-1c3a-4f5b-9d6e-2a8b1c4d5e6f",
      "type": "athlete",
      "label": "L. Marchetti",
      "home_or_travel": "home",
      "started_at": "2026-04-15T08:30:00Z",
      "ended_at": "2026-05-20T14:00:00Z",
      "notes": "Pre-season recovery tracking"
    },
    {
      "assignment_id": "...",
      "type": "place",
      "label": "Recovery Bed 3",
      "started_at": "2026-05-20T14:05:00Z",
      "ended_at": null
    }
  ]
}

Step 2: pull the readings, scoped

Pass the assignment_id to the readings endpoint. The time window defaults to the assignment’s [started_at, ended_at), so you don’t have to compute timestamps yourself:
curl -H "Authorization: Bearer $ST_API_KEY" \
  "https://api.1st.app/v1/devices/<device_id>/readings?assignment_id=f4e9b8d2-1c3a-4f5b-9d6e-2a8b1c4d5e6f"
Or for a bulk CSV that you can drop into a spreadsheet:
curl "https://api.1st.app/v1/readings.csv?assignment_id=f4e9b8d2-1c3a-4f5b-9d6e-2a8b1c4d5e6f" \
  -H "Authorization: Bearer $ST_API_KEY" \
  -o marchetti-preseason.csv
That’s the entire flow.

When you’d combine it with a date range

Sometimes you only want a slice of a block, say the last 7 days the athlete had the device. Pass both:
curl -H "Authorization: Bearer $ST_API_KEY" \
  "https://api.1st.app/v1/devices/<device_id>/readings?assignment_id=f4e9b8d2-1c3a-4f5b-9d6e-2a8b1c4d5e6f&last=7d"
The result is the intersection of your date range and the assignment’s period. If your range falls entirely outside the assignment’s window, you get an empty page, not an error.

When you’d skip the assignment_id

For “show me the latest from every device on the team,” you don’t need assignments at all. GET /v1/devices/current and the plain ?last=24h queries cover that. Reach for ?assignment_id= when the question is about a specific block of usage in the past.

AI prompt template

Paste this into Claude or ChatGPT and fill in the brackets:
Read https://dev.1st.app/llms-full.txt. That's the full reference
for the 1st sensor platform API.

For my team's device with display_name "[name]", give me a
[Google Apps Script | Airtable Script | Python script] that pulls
the CO2 + temp readings for the assignment matching label
"[athlete name]" and writes them to [Sheets / Airtable / CSV].

Use `?assignment_id=` so the data is scoped to just the time the
athlete had the device.

The API key is in [PropertiesService.ST_API_KEY | env var
ST_API_KEY | Airtable secret]. Don't put the key in the code.
The AI will list the device’s assignments first to find the matching assignment_id, then pull the readings.

Errors you might hit

  • assignment_not_found — the ID isn’t on the device you asked about (or isn’t visible to your team). List the device’s assignments to get a valid one. More.
  • validation_failed with param: assignment_id — the value isn’t a UUID. The shape is 00000000-0000-0000-0000-000000000000.
  • cursor_device_mismatch — your ?cursor=... was issued for a different device. Drop the cursor when you switch devices. More.