Recipes

Ready-made building blocks for the things every integration needs — authenticating once, paginating through a list, and streaming a full history. Copy, paste, and wire in your keys.

A tiny API client

Set the two key headers once, then call any path. It unwraps the response envelope and throws on any non-2xx so your own code only ever sees data.

JavaScript
const BASE = "https://api.lucideld.com";
const headers = {
  "X-API-Provider-Key": process.env.PROVIDER_KEY,
  "X-API-Company-Key": process.env.COMPANY_KEY,
};

// GET a path and unwrap the envelope. Throws on any non-2xx.
async function api(path) {
  const res = await fetch(BASE + path, { headers });
  const body = await res.json();
  if (!res.ok) throw new Error(res.status + " " + (body.description || res.statusText));
  return body; // { description, data, page, total_pages, ... }
}
Python
import os, requests

BASE = "https://api.lucideld.com"
HEADERS = {
    "X-API-Provider-Key": os.environ["PROVIDER_KEY"],
    "X-API-Company-Key": os.environ["COMPANY_KEY"],
}

def api(path):
    """GET a path and unwrap the envelope. Raises on any non-2xx."""
    res = requests.get(BASE + path, headers=HEADERS, timeout=30)
    body = res.json()
    if not res.ok:
        raise RuntimeError(f"{res.status_code} {body.get('description', res.reason)}")
    return body  # {"description", "data", "page", "total_pages", ...}

Fetch every page

Most list endpoints (drivers, vehicles, statuses) are page-based. Loop from page 1 and stop once you reach total_pages. Reuses the api() helper above.

JavaScript
// Walk every page of a list endpoint and collect all records.
async function fetchAll(path, limit = 100) {
  const all = [];
  for (let page = 1; ; page++) {
    const sep = path.includes("?") ? "&" : "?";
    const body = await api(path + sep + "page=" + page + "&limit=" + limit);
    all.push(...body.data);
    if (page >= body.total_pages) break;
  }
  return all;
}

const drivers = await fetchAll("/v2/drivers");
Python
def fetch_all(path, limit=100):
    """Walk every page of a list endpoint and collect all records."""
    records, page = [], 1
    while True:
        sep = "&" if "?" in path else "?"
        body = api(f"{path}{sep}page={page}&limit={limit}")
        records.extend(body["data"])
        if page >= body["total_pages"]:
            break
        page += 1
    return records

drivers = fetch_all("/v2/drivers")

Stream all location history

Vehicle Location History is token-based, not page-based. Pass the next_page_token from each response until it stops coming back. Yielding keeps memory flat over a six-month range.

JavaScript
// Page through location history with the next_page_token cursor.
async function* locationHistory(vehicleId, startDate, endDate) {
  let token = null;
  do {
    const params = new URLSearchParams({
      start_date: startDate,
      end_date: endDate,
      limit: "1000",
    });
    if (token) params.set("next_page_token", token);
    const body = await api("/v2/vehicle-location-history/" + vehicleId + "?" + params);
    yield* body.data;
    token = body.next_page_token || null;
  } while (token);
}

for await (const ping of locationHistory(vehicleId, "03-30-2026", "04-01-2026")) {
  // ping.lat, ping.lng, ping.timestamp, ...
}
Python
from urllib.parse import urlencode

def location_history(vehicle_id, start_date, end_date):
    """Yield every GPS breadcrumb across the token-paginated pages."""
    token = None
    while True:
        params = {"start_date": start_date, "end_date": end_date, "limit": 1000}
        if token:
            params["next_page_token"] = token
        body = api(f"/v2/vehicle-location-history/{vehicle_id}?{urlencode(params)}")
        yield from body["data"]
        token = body.get("next_page_token")
        if not token:
            break

for ping in location_history(vehicle_id, "03-30-2026", "04-01-2026"):
    ...  # ping["lat"], ping["lng"], ping["timestamp"]
Staying in sync
The API is polling-based. Refresh the latest-status endpoints on an interval matched to how often the data actually moves — motion data refreshes roughly every 60 seconds, so polling faster just returns the same values. Back off when you get a 429. See Errors for the full list.