Skip to content

Tracker SDK Guide

The Urban Sky SDK provides a complete tracker management interface for creating trackers, uploading GPS data, and querying positions and sessions.

Table of Contents

Quick Start

JavaScript

javascript
const { UrbanSkySDK } = require('@urbansky/sdk')

const sdk = await UrbanSkySDK.init({
  apiToken: 'your-api-token',
})

// Create a tracker
const tracker = await sdk.createTracker({ name: 'Field Unit', type: 'GPS' })

// Upload points
await sdk.ingestPoints(tracker.id, [
  { latitude: 39.74, longitude: -104.99, timestamp: Date.now(), altitude: 1609 },
])

// Query sessions
const { sessions } = await sdk.getTrackerSessions(tracker.id)
const { messages } = await sdk.getSessionPoints(sessions[0].id)

Python

python
from urbansky_sdk import UrbanSkySDK

sdk = await UrbanSkySDK.init({
  'apiToken': 'your-api-token',
})

# Create a tracker
tracker = sdk.create_tracker(name='Field Unit', type='GPS')

# Upload points
import time
sdk.ingest_points(tracker.id, [
  {'latitude': 39.74, 'longitude': -104.99, 'timestamp': int(time.time() * 1000), 'altitude': 1609},
])

# Query sessions
sessions = sdk.get_tracker_sessions(tracker.id)
points = sdk.get_session_points(sessions.sessions[0].id)

Required Scopes

Every tracker endpoint is scope-gated. Your API token needs the right allowed_resources entry to call each operation. A 403 Forbidden on a call that used to work means your token's scopes need to be updated.

OperationMethodRequired scope
listTrackers, getTrackerSessions, getSessionPoints, getLatestPositionsGETtrackers:read
createTrackerPOSTtrackers:write
updateTrackerPATCHtrackers:write
shareTracker, revokeTrackerSharePOSTtrackers:write
ingestPointsPOSTtrackers:ingest
Any of the abovetrackers:*

API tokens that existed before this SDK release were auto-granted trackers:read only. Write / ingest must be granted explicitly. See the release notes for the inventory SQL and grant playbook.

Creating Trackers

Create a tracker before uploading data. You can provide your own ID or let the system generate one.

JavaScript

javascript
// Auto-generated ID
const tracker = await sdk.createTracker({
  name: 'Vehicle GPS',
  type: 'GPS',
})
console.log(tracker.id) // e.g. "a1b2c3d4-..."

// Custom ID
const tracker2 = await sdk.createTracker({
  id: 'truck-42',
  name: 'Truck 42',
  type: 'FLEET',
})

Python

python
# Auto-generated ID
tracker = sdk.create_tracker(name='Vehicle GPS', type='GPS')

# Custom ID
tracker2 = sdk.create_tracker(id='truck-42', name='Truck 42', type='FLEET')

Parameters:

FieldTypeRequiredDescription
idstringNoCustom tracker ID. Auto-generated if omitted
namestringYesDisplay name for the tracker
typestringNoTracker type (e.g. gps, fleet). Defaults to custom. Case-insensitive on input; always returned lowercase.

Ingesting Points

Upload GPS points for a tracker. Points are stored immediately and become queryable via sessions.

Create before ingesting

You must call createTracker before sending points. The ingest endpoint returns 404 Tracker not found for non-existent ids — there is no auto-create. createTracker requires the trackers:write scope; ingestPoints requires trackers:ingest (see Required Scopes).

JavaScript

javascript
await sdk.ingestPoints('truck-42', [
  {
    latitude: 39.7392,
    longitude: -104.9903,
    timestamp: 1705753800000, // Unix epoch milliseconds
    altitude: 1609, // Optional, meters
    metadata: { speed: 45.2, heading: 270 }, // Optional
  },
  {
    latitude: 39.74,
    longitude: -104.989,
    timestamp: 1705753860000,
    altitude: 1615,
  },
])

Python

python
sdk.ingest_points('truck-42', [
  {
    'latitude': 39.7392,
    'longitude': -104.9903,
    'timestamp': 1705753800000,
    'altitude': 1609,
    'metadata': {'speed': 45.2, 'heading': 270},
  },
  {
    'latitude': 39.7400,
    'longitude': -104.9890,
    'timestamp': 1705753860000,
    'altitude': 1615,
  },
])

Point fields:

FieldTypeRequiredDescription
latitudenumberYesLatitude (-90 to 90)
longitudenumberYesLongitude (-180 to 180)
timestampnumberYesUnix epoch in milliseconds
altitudenumberNoAltitude in meters
metadataobjectNoArbitrary key-value pairs

Limits: Up to 10,000 points per request. For larger datasets, batch your calls.

Querying Trackers

List All Trackers

javascript
// JavaScript
const { trackers } = await sdk.listTrackers()
trackers.forEach(t => {
  console.log(`${t.name} (${t.type}) - ${t.isActive ? 'active' : 'inactive'}`)
})

// Filter by name or type
const { trackers: gps } = await sdk.listTrackers({ type: 'GPS' })
const { trackers: search } = await sdk.listTrackers({ name: 'truck' })
python
# Python
result = sdk.list_trackers()
for t in result.trackers:
  print(f'{t.name} ({t.type}) - {"active" if t.is_active else "inactive"}')

# Filter
gps = sdk.list_trackers(type='GPS')
search = sdk.list_trackers(name='truck')

Latest Positions

Get the most recent position for every tracker in your organization.

javascript
// JavaScript
const { positions } = await sdk.getLatestPositions()
positions.forEach(p => {
  console.log(`${p.trackerName}: ${p.latitude}, ${p.longitude} (${p.lastTime})`)
})
python
# Python
latest = sdk.get_latest_positions()
for p in latest.positions:
  print(f'{p.tracker_name}: {p.latitude}, {p.longitude} ({p.last_time})')

Sessions & Points

Tracker data is automatically organized into sessions based on time gaps. If a tracker goes silent for longer than its session timeout (default: 6 hours), a new session starts when data resumes.

Get Sessions

javascript
// JavaScript
const { sessions } = await sdk.getTrackerSessions('truck-42', { limit: 10 })
sessions.forEach(s => {
  console.log(`${s.startTime} → ${s.endTime} (${s.messageCount} points)`)
})
python
# Python
result = sdk.get_tracker_sessions('truck-42', limit=10)
for s in result.sessions:
  print(f'{s.start_time}{s.end_time} ({s.message_count} points)')

Get Session Points

Retrieve the actual GPS points for a specific session.

javascript
// JavaScript
const { messages } = await sdk.getSessionPoints(sessions[0].id, { limit: 300 })
messages.forEach(m => {
  console.log(`[${m.time}] ${m.latitude}, ${m.longitude}`)
})
python
# Python
result = sdk.get_session_points(sessions[0].id, limit=300)
for m in result.messages:
  print(f'[{m.time}] {m.latitude}, {m.longitude}')

Session IDs

Session IDs use the format trackerId:startTimeMs (e.g. truck-42:1705234800000). You don't need to construct these yourself — they're returned by getTrackerSessions.

Scan window

The session endpoints read up to the last 730 days (~2 years) of tracker history. Sessions older than that aren't returned by getTrackerSessions; sessions longer than 2 years are truncated to their first 730 days of messages. This covers the common balloon flight use case (typical sessions ≤ 1 year).

Updating Trackers

javascript
// JavaScript
const updated = await sdk.updateTracker('truck-42', {
  name: 'Truck 42 (Retired)',
  sessionTimeoutHours: 24, // 1-336 hours
  alias: 'Old Faithful',
  groundPinned: true,
})
python
# Python
updated = sdk.update_tracker(
  'truck-42',
  name='Truck 42 (Retired)',
  session_timeout_hours=24,
  alias='Old Faithful',
  ground_pinned=True,
)

Updatable fields:

FieldTypeDescription
namestringDisplay name
typestringTracker type
sessionTimeoutHoursnumberHours of silence before new session (1-336)
aliasstring | nullUser-friendly name override
iconstring | nullIcon type for map display
groundPinnedbooleanPin tracker to ground level on map

API Reference

JavaScript Methods

MethodReturnsDescription
createTracker(options)CreateTrackerResponseCreate a new tracker
listTrackers(options?)TrackerListResponseList organization trackers
updateTracker(id, options)UpdateTrackerResponseUpdate tracker properties
ingestPoints(trackerId, points)IngestPointsResponseUpload GPS points
getTrackerSessions(trackerId, options?)TrackerSessionsResponseGet sessions for a tracker
getSessionPoints(sessionId, options?)SessionPointsResponseGet points for a session
getLatestPositions()LatestPositionsResponseLatest position per tracker

Python Methods

MethodReturnsDescription
create_tracker(name, type?, id?)CreateTrackerResponseCreate a new tracker
list_trackers(name?, type?)TrackerListResponseList organization trackers
update_tracker(tracker_id, **kwargs)UpdateTrackerResponseUpdate tracker properties
ingest_points(tracker_id, points)IngestPointsResponseUpload GPS points
get_tracker_sessions(tracker_id, limit?)TrackerSessionsResponseGet sessions for a tracker
get_session_points(session_id, limit?)SessionPointsResponseGet points for a session
get_latest_positions()LatestPositionsResponseLatest position per tracker

Next Steps