Lesen
Erlaubt GET-Endpunkte. Wähle diese Berechtigung, wenn die Integration Kontodaten nur anzeigen oder exportieren muss.
Verbinde eine serverseitige Integration mit den Daten, die bereits mit einem Lunidex-Konto synchronisiert wurden. Erstelle einen Schlüssel und sende eine erste Anfrage. Danach folgen Karten, Sealed-Produkte, Pagination und sichere Schreibzugriffe.
Ein API-Schlüssel gehört niemals in Browsercode, eine mobile App, ein öffentliches Repository, eine URL, einen Screenshot oder ein gemeinsam genutztes Protokoll. Speichere ihn in einem serverseitigen Secret-Manager und sende ihn nur im Authorization-Header.
Die Integration benötigt einen Schlüssel, ein serverseitig gespeichertes Secret und eine HTTPS-Anfrage an die API-Basis-URL.
Öffne die API-Schlüsselkarte im Lunidex-Dashboard. Vergib einen Namen und wähle Lesezugriff oder Lese- und Schreibzugriff. Das vollständige Secret wird nur einmal angezeigt. Kopiere es, bevor du die Meldung schließt.
Speichere den Schlüssel als LUNIDEX_API_KEY im Secret-Manager deines Hosting-Anbieters. Committe ihn nicht und sende ihn nicht an den Browser.
Rufe GET /me von deinem Backend auf. Private Endpunkte benötigen den Header Authorization: Bearer gefolgt vom Schlüssel.
curl --fail-with-body \
-H "Authorization: Bearer $LUNIDEX_API_KEY" \
https://lunidex.app/api/v1/meconst API_BASE_URL = "https://lunidex.app/api/v1";
const apiKey = process.env.LUNIDEX_API_KEY;
if (!apiKey) throw new Error("Missing LUNIDEX_API_KEY");
const response = await fetch(API_BASE_URL + "/me", {
headers: { Authorization: "Bearer " + apiKey },
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.code ?? "REQUEST_FAILED");
}
console.log(result.data);Sende den Schlüssel bei jeder privaten /api/v1-Anfrage im HTTP-Header Authorization. Die API liefert JSON in einem data-Umschlag; private Antworten verwenden Cache-Control: private, no-store.
Erlaubt GET-Endpunkte. Wähle diese Berechtigung, wenn die Integration Kontodaten nur anzeigen oder exportieren muss.
Erlaubt GET- und Schreibendpunkte. Verwende sie nur für eine vertrauenswürdige Serverintegration, die die Sammlung oder das Sealed-Transaktionsjournal ändern muss.
Die API sieht nur Daten, die mit dem Lunidex-Konto in Neon synchronisiert wurden. Daten, die nur auf einem Gerät liegen, sind nicht verfügbar. Die Kontoidentität enthält keine E-Mail-Adresse.
Listen liefern data und meta.nextCursor. Übernimm den Cursor unverändert für die nächste Seite und beende die Abfrage, wenn er null ist.
const API_BASE_URL = "https://lunidex.app/api/v1";
const apiKey = process.env.LUNIDEX_API_KEY;
let cursor = null;
if (!apiKey) throw new Error("Missing LUNIDEX_API_KEY");
do {
const query = new URLSearchParams({ limit: "100" });
if (cursor) query.set("cursor", cursor);
const response = await fetch(API_BASE_URL + "/cards?" + query, {
headers: { Authorization: "Bearer " + apiKey },
});
const result = await response.json();
if (!response.ok) throw new Error(result.error?.code ?? "REQUEST_FAILED");
console.log(result.data);
cursor = result.meta?.nextCursor ?? null;
} while (cursor);Die Pfade sind relativ zur API-Basis-URL. Jede Zeile zeigt die erforderliche Berechtigung und die im OpenAPI-Vertrag aufgeführten Parameter. Die maschinenlesbare Spezifikation enthält vollständige Schemas, Anfrage- und Antwortbeispiele sowie Fehler pro Operation; die folgenden Abschnitte erklären die wichtigsten Abläufe.
/openapi.jsonÖffentlicher maschinenlesbarer Vertrag; kein API-Schlüssel erforderlich.
/meBegrenzte Kontoidentität ohne E-Mail-Adresse.
/summaryWichtige Kontostatistiken, physische und unterschiedliche Kartenzahlen sowie Sealed-Summen in EUR-Cent.
/cardsPaginierte Kartenbestände mit optionalen Sprach- und Set-Filtern.
cursor(Abfrage)limit(Abfrage)language(Abfrage)set(Abfrage)/cards/{cardId}TCGdex-Metadaten und eigene Bestände; keine Kartenbewertungen.
cardId(Pfad)· erforderlichlanguage(Abfrage)/cards/{cardId}Setzt die absolute Menge für Sprache und Kartenvariante.
cardId(Pfad)· erforderlich/sealed/catalogueDurchsucht den vorhandenen Cardmarket-Katalog für Sealed-Produkte.
q(Abfrage)cursor(Abfrage)/sealed/positionsAktuelle paginierte Positionen mit Kosten und gespeichertem Marktwert.
cursor(Abfrage)limit(Abfrage)language(Abfrage)productId(Abfrage)/sealed/positions/{productId}Aktuelle Sprachpositionen für ein besessenes Produkt.
productId(Pfad)· erforderlich/sealed/transactionsPrivates Transaktionsjournal mit Revisionen und Filtern.
cursor(Abfrage)limit(Abfrage)language(Abfrage)productId(Abfrage)type(Abfrage)includeVoided(Abfrage)voided(Abfrage)/sealed/transactionsErstellt Kauf, Verkauf oder Tausch; Idempotency-Key erforderlich.
Idempotency-Key(Header)· erforderlich/sealed/transactions/{id}Liest eine Transaktion dieses Kontos.
id(Pfad)· erforderlich/sealed/transactions/{id}Ändert eine Transaktion mit Revisionsprüfung.
id(Pfad)· erforderlich/sealed/transactions/{id}/voidStorniert eine Transaktion mit Revisionsprüfung.
id(Pfad)· erforderlichGET /cards listet besessene Varianten auf, ohne den vollständigen TCGdex-Katalog zu laden. Jeder Bestand enthält cardId, setId, language, variant und quantity; die optionalen Filter sind language und set.
GET /cards/{cardId} liefert nützliche TCGdex-Metadaten und die Bestände dieser Karte im Konto. Mit dem Abfrageparameter language kannst du die Bestände eingrenzen.
PUT /cards/{cardId} erwartet language, variant (unspecified, normal, reverse oder holo) und eine absolute Menge von 0 bis 10.000. Mit 0 wird die Variante entfernt.
{
"language": "en",
"variant": "reverse",
"quantity": 2
}Ältere Bestände ohne Sprache bleiben sichtbar; language kann null sein und der Eintrag kann als legacy markiert sein.
Diese API gibt keine Kartenwerte zurück.
Sealed-Positionen enthalten Mengen nach Sprache, Kosten und aktuellen Wert auf Basis der bereits in Lunidex gespeicherten Preise. Beträge sind ganze EUR-Cent. Fehlt ein Preis, ist valueCents null und missingPrice gesetzt; die Zusammenfassung zählt außerdem missingPrices.
In GET /summary ist der Sealed-Wert null, wenn für mindestens ein besessenes Produkt kein Preis vorhanden ist; missingPrices enthält die Anzahl.
Suche mit q (maximal 150 Zeichen) und cursor nach Produkten im vorhandenen Cardmarket-Katalog. Jede Seite enthält höchstens 24 Produkte. Verwende die Produkt-ID in weiteren Anfragen.
GET /sealed/positions unterstützt language und productId. GET /sealed/positions/{productId} liefert die aktuelle Position eines Produkts. Diese Endpunkte zeigen aktuelle Summen, keine vollständige Preisverlaufserie.
Das private Journal unterstützt language, productId, type (buy, sell, exchange), includeVoided und voided. Revisionen ermöglichen sichere Änderungen.
PUT /cards/{cardId} setzt die Menge, statt einen Zuwachs zu addieren. Dieselbe Anfrage erneut zu senden lässt die Menge unverändert; mit 0 entfernst du die Variante. Vor dem Schreiben prüft die API Karte, Set, Sprache und verfügbare Variante.
POST /sealed/transactions akzeptiert buy, sell und exchange. Der Header Idempotency-Key (8–200 Zeichen) und expectedRevision sind erforderlich. Verwende beim erneuten Senden derselben Anfrage denselben Schlüssel, damit keine zweite Bewegung entsteht. Der erste Aufruf erstellt die Transaktion; eine Wiederholung liefert das ursprüngliche Ergebnis.
curl --request POST "https://lunidex.app/api/v1/sealed/transactions" \
-H "Authorization: Bearer $LUNIDEX_API_KEY" \
-H "Idempotency-Key: lunidex-import-example-001" \
-H "Content-Type: application/json" \
--data '{
"expectedRevision": 0,
"kind": "buy",
"cardmarketProductId": 12345,
"language": "en",
"date": "2026-09-27",
"quantity": 1,
"unitPriceCents": 2500
}'Lies vor dem Schreiben die aktuelle Journalrevision aus den Metadaten von GET /sealed/transactions und verwende sie als expectedRevision. PATCH /sealed/transactions/{id} benötigt zusätzlich die revision dieser Transaktion. Eine veraltete Revision führt zu 409. Lade Transaktion und Journal neu, bevor du über einen erneuten Versuch entscheidest.
PATCH /sealed/transactions/{id}
POST /sealed/transactions/{id}/void
POST /sealed/transactions/{id}/void benötigt revision und expectedRevision. Erstellen, Ändern und Stornieren verwenden dieselben Transaktionsprüfungen, Allokationen und Auditdaten wie Lunidex.
{
"revision": 1,
"expectedRevision": 0
}Erfolgreiche Antworten verwenden { "data": ..., "meta": ... } (meta ist optional). Fehler verwenden { "error": { "code": ..., "message": ..., "details": ... } } (details ist optional).
Häufige Antworten: 400 ungültige Transaktionsdaten; 401 ungültiger Schlüssel; 403 fehlende Berechtigung; 404 Ressource fehlt oder gehört nicht zum Konto; 409 Cursor oder Revision veraltet; 410 Konto wird gelöscht; 422 ungültiger Abfrageparameter oder Request-Body; 429 Kontingent erreicht; 500 unerwarteter Serverfehler; 502 Kartendaten nicht verfügbar; 503 API nicht verfügbar.
Bei 409 rufe die aktuelle Ressource ab oder starte die Liste ohne Cursor neu. Wandle einen Konflikt nicht blind in eine neue Transaktion um.
Eine 429-Antwort enthält Retry-After. Warte mindestens die angegebene Anzahl Sekunden, bevor du es erneut versuchst.
Alle privaten API-Antworten verwenden Cache-Control: private, no-store. Das öffentliche OpenAPI-Dokument ist separat unter /api/v1/openapi.json verfügbar.
Die Limits gelten pro Lunidex-Konto und werden von dessen API-Schlüsseln gemeinsam genutzt.
| Lesezugriffe pro Minute | 60 |
|---|---|
| Schreibzugriffe pro Minute | 10 |
| Lesezugriffe pro Tag | 1.000 |
| Schreibzugriffe pro Tag | 100 |
| Kartendetails pro Konto und Tag | 100 |
| Sealed-Berechnungen pro Konto und Tag | 100 |
| Globales Tageslimit pro kostenintensiver Kategorie | 5.000 |
Kartendetails und Sealed-Berechnungen haben außerdem getrennte globale Obergrenzen von jeweils 5.000 Vorgängen pro Tag. Eine 429-Antwort enthält Retry-After.
OpenAPI-Spezifikation öffnen