Konventionen
Konventionen
Die Regeln, die auf jedem Endpunkt gelten — hier einmal formuliert, statt auf allen fünfundzwanzig wiederholt.
Idempotenz
Endpunkte, die etwas verändern, akzeptieren einen Idempotency-Key-Header. Eine Anfrage mit demselben Schlüssel spielt die ursprüngliche Antwort erneut ab, statt die Wirkung zu wiederholen — eine Wiederholung nach einer Zeitüberschreitung kann also keinen zweiten Produktpass anlegen. Schlüssel gehören zu einer Organisation, sodass zwei Kunden nie auf demselben Wert kollidieren. Test und Live bleiben getrennt: ein im einen Modus bereits verwendeter Schlüssel wird im anderen abgelehnt statt abgespielt. Eine Ausnahme, und zwar eine Berechtigung statt einer Tatsache: Die von `POST /documents` zurückgegebene signierte Upload-URL wird bei einer Wiederholung neu ausgestellt, solange die Datei noch aussteht, und entfällt, sobald sie eingegangen ist — eine abgelaufene URL wäre die getreue Wiedergabe von nichts Brauchbarem.
Ein Schlüssel bleibt 30 Tage lang gespeichert. Danach ist er vollständig vergessen, und eine Wiederholung damit läuft erneut durch, statt abgespielt zu werden — ein Abgleichlauf, der später einsetzen kann, sollte daher einen frischen Schlüssel erzeugen.
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports" \
-X POST \
-H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"category":"textile"}'Blätterung
Sammlungen werden per Cursor geblättert, niemals per Offset. Ein Offset ist bei gleichzeitigen Schreibvorgängen schlicht falsch: ein zwischen zwei Seitenabrufen eingefügter Datensatz verschiebt jeden späteren, und ein Client überspringt oder verdoppelt Zeilen, ohne es zu merken.
Senden Sie next_cursor als cursor zurück, um die nächste Seite zu holen. Ein Cursor kodiert die Filter, unter denen er ausgegeben wurde; mit anderen Filtern wird er abgelehnt, statt eine Seite zu liefern, die stillschweigend etwas anderes bedeutet.
{
"object": "list",
"data": [],
"has_more": true,
"next_cursor": "eyJjIjoiMjAyNi0wOC0wMVQxNDowMzoyMi41MDFaIn0"
}Bedingte Schreibvorgänge
Beim Lesen eines Produktpasses kommt ein ETag mit seiner Version zurück. Senden Sie es als If-Match an einem PATCH zurück, dann wird der Schreibvorgang abgelehnt, falls sich der Produktpass zwischenzeitlich geändert hat — der einzige Weg, ein Lesen-Ändern-Schreiben gegen einen gleichzeitig arbeitenden Bearbeiter abzusichern.
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports/{id}" \
-X PATCH \
-H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
-H "If-Match: \"4\"" \
-H "Content-Type: application/json" \
-d '{"data":{"recycled_content_percentage":38}}'Ratenbegrenzungen
Bei jeder Anfrage mit Zugangsschlüssel laufen drei Zähler gleichzeitig, und der engste entscheidet. Die veröffentlichten Werte sind bewusst vorsichtige Ausgangspunkte, keine austarierten Obergrenzen.
| Zähler | Anfragen | Zeitfenster |
|---|---|---|
| key_org | 1000 | 60s |
| organization | 3000 | 60s |
| credential | 10000 | 60s |
| destructive | 50 | 3600s |
Jede gezählte Antwort führt RateLimit- und RateLimit-Policy-Header mit, die den Zähler benennen, der seiner Grenze am nächsten kam. Eine Ablehnung ergänzt Retry-After. Warten Sie diese Zeit ab, statt zu raten.
Eine Anfrage ohne brauchbaren Zugangsschlüssel zählt gegen einen eigenen, deutlich engeren Zähler von 60 Anfragen pro Minute je Clientadresse. Für einen gültigen Schlüssel gilt er nie.
Anfragegröße
Ein Anfragekörper über der Obergrenze seines Endpunkts wird mit payload_too_large abgelehnt, bevor irgendetwas Richtung Datenbank gelesen wird. Die Obergrenze wird zweimal geprüft: zuerst gegen die angegebene Content-Length, was nichts kostet, und dann gegen die tatsächlich eintreffenden Bytes — so bleibt auch eine Anfrage ohne Längenangabe begrenzt.
| Endpunkte | Obergrenze |
|---|---|
| Jeder Endpunkt, der einen einzelnen Datensatz schreibt | 256 KiB (262144 bytes) |
| Massenimport und Einheiten-Stapel | 4 MiB (4194304 bytes) |
Die Obergrenze für Stapel folgt dem größten Stapel, den diese API annimmt, nicht einer runden Zahl: 500 Importzeilen mit jedem Feld einer Kategorie befüllt oder 1000 serialisierte Einheiten. Keiner von beiden passt in die Standardobergrenze — genau deshalb haben diese beiden Endpunkte eine eigene.
Ein Anfragekörper muss als application/json eintreffen; application/merge-patch+json wird ebenfalls angenommen. Alles andere wird mit unsupported_media_type abgelehnt, statt im Parser zu scheitern — der Fall, den man kennen sollte, ist curl -d: es sendet application/x-www-form-urlencoded, sofern nichts anderes angegeben wird. Ein Körper ganz ohne Content-Type wird als JSON gelesen.
HTTP-Methoden
Ein Endpunkt beantwortet nur die Methoden, die er dokumentiert. Jede andere Methode wird mit method_not_allowed abgelehnt, zusammen mit einem Allow-Header, der die funktionierenden nennt — wer zum falschen Verb greift, erfährt das richtige also aus der Ablehnung selbst. HEAD funktioniert überall dort, wo GET funktioniert, und OPTIONS überall.
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, PATCH, OPTIONS
Content-Type: application/json
{
"error": {
"code": "method_not_allowed",
"documentation_url": "https://passportcraft.com/docs/api/errors#method_not_allowed",
"request_id": "req_9Fv2KpQ0aXbT4Lmn",
"details": { "method": "DELETE", "allowed": ["GET", "HEAD", "PATCH", "OPTIONS"] }
}
}Destruktive Operationen
Einen Produktpass zurückzuziehen und einen in den Papierkorb zu verschieben nimmt jeweils einen veröffentlichten Datensatz vom Markt. Beide zahlen daher auf eine eigene Obergrenze neben der gewöhnlichen Ratenbegrenzung ein: eine Schleife billiger, wohlgeformter Anfragen darf keinen ganzen Katalog dunkel schalten können.
Ein Dokument an ein Feld anhängen
Manche URL-Felder nehmen statt eines Links auch eine hochgeladene Datei entgegen – etwa einen Prüfbericht oder eine Konformitätserklärung. Laden Sie die Datei zuerst hoch und verweisen Sie das Feld anschließend darauf, indem Sie die Dokument-ID in den Begleitschlüssel dieses Feldes in `data` schreiben. Das Feld selbst darf leer bleiben: Ein dokumentfähiges Feld gilt als ausgefüllt, sobald ein Dokument angehängt ist – ein Produktpass mit leerer URL kann also trotzdem validiert und veröffentlicht werden.
Sie müssen diesen Schlüssel nie selbst zusammensetzen. Ein Feld, das Dokumente annimmt, führt im Kategorieschema zwei Attribute: `document_types` mit den zulässigen Dokumentarten und `document_id_key` mit dem exakt zu schreibenden Schlüssel. Lesen Sie den Schlüssel aus dem Schema, statt sich auf die Namensregel zu verlassen – das ist der einzige unterstützte Weg. Der Begleitschlüssel ist eine Eigenschaft des Feldes und kein eigenes Feld; in der Liste `fields` des Schemas taucht er deshalb nicht auf.
Eine Regel, die das Schema nicht ausbuchstabiert: Der `access_tier` des Dokuments muss dem des Feldes entsprechen. Ein öffentliches Dokument kann ein Feld der Stufe „authority“ nicht erfüllen; das Anhängen wird mit `access_tier_mismatch` abgelehnt, denn ein Dokument mit abweichender Stufe würde dort, wo das Feld erscheint, gar nicht angezeigt. Legen Sie das Dokument mit dem `access_tier` an, den der Felddeskriptor nennt.
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports/{id}" \
-X PATCH \
-H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"data":{"conformity_declaration_url__document_id":"doc_123"}}'Leeren Sie den Begleitschlüssel, um das Dokument zu lösen; die Datei bleibt in Ihrer Bibliothek, bis Sie sie löschen. Wird ein Dokument gelöscht, auf das noch ein Feld verweist, meldet die Antwort, was dabei gelöst wurde – und diese Meldung erreicht nur den Aufrufer, der die Anfrage gestellt hat.
Der `upload_state` eines Dokuments ist `ready`, `pending` oder `unknown`. `unknown` bedeutet, dass wir nicht feststellen konnten, ob die Bytes im Speicher liegen — entweder hat der Speicher nicht geantwortet, oder der Datensatz lag jenseits der 25 Dokumente ohne Bytes, die eine Anfrage prüft. Werten Sie das als unbestimmt, nicht als fehlend: Beim Veröffentlichen führt `unknown` zu `storage_unavailable` statt zu der Aussage, eine Datei fehle, und ein späterer Abruf klärt es in der Regel.
Anfragekennungen
Jede Antwort führt einen Request-Id-Header mit, im Erfolgsfall genauso wie im Fehlerfall. Nennen Sie ihn in einer Supportanfrage, dann lässt sich genau dieser Aufruf wiederfinden.
Der Ereignis-Feed hält 30 Tage Historie vor. Eine Integration, die seltener abfragt, verpasst Änderungen und sollte stattdessen gegen die Produktpass-Liste abgleichen.