Zum Inhalt springen

Einheiten in Ihr System übernehmen

Übernehmen Sie die Einheiten Ihrer Organisation mit Cursor-Paginierung in ERP, MES oder Datenbank, setzen Sie nach einer Unterbrechung fort und erkennen Sie Änderungen.

listBatteries liefert die Einheiten (einzelne Batterien) Ihrer Organisation Seite für Seite. Diese Anleitung liest alle, speichert den Cursor, damit ein unterbrochener Lauf weitermachen kann, und zeigt, wie Sie erkennen, welche Einheiten sich seit dem letzten Lauf geändert haben. Sie brauchen einen Schlüssel mit dem Scope read.

Um Änderungen zu bemerken, ohne jede Einheit erneut zu lesen, fragen Sie den Änderungsfeed listChanges ab; der Ablauf Pass-Links zurück ins ERP zeigt, wie.

Die Liste

cURL
curl -sS "$BATTERYPASS_URL/api/v1/batteries?limit=200&passport_status=published" \
  -H "Authorization: Bearer $BATTERYPASS_API_KEY"
200 (gekürzt)
{
  "items": [
    {
      "id": "0192a3f0-5b7c-7d21-8e4f-6a2b9c1d3e5f",
      "serial_number": "SV2027-000184",
      "battery_model_id": "0192f0a1-6c2e-7d4b-9a10-3e5f7b2c8d41",
      "model_version_id": "0192f0a2-1b3c-7e5d-8f60-7a8b9c0d1e2f",
      "battery_status": "original",
      "passport_status": "published",
      "manufacturing_date": "2026-06-18",
      "facility_id": "0192f09e-4a5b-7c6d-9e8f-0a1b2c3d4e5f",
      "identifiers_locked_at": "2026-07-02T10:15:00Z",
      "successor_battery_ids": [],
      "row_version": 4,
      "created_at": "2026-06-20T08:00:12Z",
      "updated_at": "2026-07-02T10:15:00Z"
    }
  ],
  "next_cursor": "eyJTZXJpYWxOdW1iZXIiOiJTVjIwMjctMDAwMTg0IiwiSUQiOiIwMTkyYTNmMC01YjdjLTdkMjEtOGU0Zi02YTJiOWMxZDNlNWYifQ"
}

Die Einheiten sind nach Seriennummer, dann ID sortiert. limit liegt zwischen 1 und 200 (Standard 50). next_cursor ist auf der letzten Seite null. Diese Filter schränken die Liste ein und lassen sich kombinieren:

ParameterNur Einheiten,
battery_model_iddie zu diesem Batteriemodell gehören
model_version_iddie zu dieser Modellversion gehören
passport_statusderen Pass diesen Status hat: draft, qr_locked, published, update_needed, suspended, withdrawn, deleted_recycled
serial_prefixderen Seriennummer mit diesem Text beginnt (1 bis 50 Zeichen)
import_iddie dieser Tabellenimport angelegt hat

Einen Filter nach Änderungsdatum gibt es nicht. Änderungen erkennen Sie auf Ihrer Seite, wie weiter unten beschrieben.

Alle Seiten lesen

Behalten Sie in einem Lauf für jede Seite dieselben Filter bei, und speichern Sie den Cursor erst, nachdem Sie die zugehörige Seite gespeichert haben. Ist der Lauf vollständig, löschen Sie den Cursor, damit der nächste Lauf von vorn beginnt.

// sync-units.mts: npx tsx sync-units.mts
import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs';

const BASE = `${process.env.BATTERYPASS_URL}/api/v1`;
const headers = { Authorization: `Bearer ${process.env.BATTERYPASS_API_KEY}` };
const STATE = 'units.cursor'; // lets an interrupted pass continue where it stopped

type Unit = { id: string; serial_number: string; passport_status: string; row_version: number };

// Placeholder: insert or update the unit in your database, keyed by id.
function upsert(unit: Unit) {
  console.log(unit.id, unit.serial_number, unit.passport_status, unit.row_version);
}

let cursor: string | null = existsSync(STATE) ? readFileSync(STATE, 'utf8') : null;
do {
  const query = new URLSearchParams({ limit: '200' });
  if (cursor) query.set('cursor', cursor);
  const res = await fetch(`${BASE}/batteries?${query}`, { headers });
  if (!res.ok) throw new Error(`listBatteries: ${res.status} ${(await res.json()).code}`);
  const page: { items: Unit[]; next_cursor: string | null } = await res.json();
  page.items.forEach(upsert);
  cursor = page.next_cursor;
  if (cursor) writeFileSync(STATE, cursor); // only after the page is stored
} while (cursor);
rmSync(STATE, { force: true }); // pass complete: the next one starts at the beginning

Was der Cursor ist und was nicht

  • Der Cursor ist undurchsichtig: Speichern Sie ihn unverändert und senden Sie ihn so zurück. Er läuft nicht ab.
  • Er markiert eine Position in der Reihenfolge der Seriennummern, keinen Zeitpunkt. Eine Einheit, die während eines Laufs angelegt wird und deren Seriennummer vor dem Cursor einsortiert ist, fehlt im Rest dieses Laufs; der nächste Lauf findet sie. Fragen Sie mit einem gespeicherten Cursor also nicht „was ist seit dem letzten Mal neu“: Jeder Lauf ist ein vollständiger Durchgang, und der Cursor lässt nur einen unterbrochenen Durchgang fortsetzen.
  • Lehnt BatteryPass einen gespeicherten Cursor ab (400 validation_error auf cursor), löschen Sie ihn und beginnen einen neuen Durchgang.

Paginierung beschreibt die Regeln für alle Listen.

Änderungen erkennen

Vergleichen Sie jede Einheit mit dem, was Sie im vorigen Lauf gespeichert haben:

Was sich geändert hatWoran Sie es erkennen
Eine neue EinheitEine id, die Sie noch nicht gespeichert haben
Die eigenen Daten der Einheit (Seriennummer, Datumsangaben, Standort, battery_status, Modellversion, gesperrte Kennungen)row_version ist höher und updated_at später
Der Passstatus, z. B. published → update_neededpassport_status weicht ab; row_version ändert sich dadurch nicht
Eine neue Passversioncurrent_version.version_no von getPassport ist höher
Werte der Einheitrevision und recorded_at je Feld in listBatteryValues

Über die API werden Einheiten nie gelöscht; eine Batterie am Ende ihres Lebens zeigt das in battery_status und passport_status. Die Werte jeder Einheit zu lesen kostet eine Anfrage pro Einheit: Beschränken Sie das auf Einheiten, deren Status oder Version sich geändert hat, oder verteilen Sie es auf mehrere Läufe. Das Rezept Data-Warehouse-Abgleich schreibt Einheiten und Werte als JSON Lines.

Limits

Alle Schlüssel Ihrer Organisation teilen sich 600 Anfragen pro Minute. Ein vollständiger Durchgang über 10 000 Einheiten mit limit=200 braucht 50 Anfragen; die Werte jeder Einheit zu lesen kostet weitere 10 000. Auf 429 rate_limited reagieren Sie, indem Sie Retry-After abwarten (Ratenlimits, Fehler und Wiederholungen).

Auf dieser Seite