Persistenz-API
Ein Project anlegen, Fracht importieren, eine Berechnung starten und den gespeicherten Ladeplan lesen.
Die Persistenz-API ist REST unter /api/v1 auf dem Origin der App, zum Beispiel https://app.example.com/api/v1. Das OpenAPI-3.1-Dokument liegt unter /api/v1/spec.json, und /api/v1 selbst zeigt die Scalar-Referenz, in der Sie jede Route ausprobieren können. Für Postman importieren Sie /api/v1/postman.json, und der API-Schnellstart zeigt den ganzen Ablauf. Das ist nicht der Cookie-Baum /rpc und nicht die Admin-Referenz unter /api-reference.
Jede Route, jedes Feld und jeder Fehlercode unten wird aus einem Vertrag erzeugt, daher entspricht die Spezifikation unter /api/v1/spec.json immer dem Verhalten des Servers. Erzeugen Sie Ihren Client daraus, statt Strukturen von Hand abzuschreiben.
Authentifizierung
Senden Sie bei jeder Anfrage einen API-Schlüssel der Organisation als Bearer-Token:
Authorization: Bearer sc_live_…
Das Geheimnis wird in der App unter API-Schlüssel einmal angezeigt, und gespeichert wird nur ein Hash. Inhaber und Admins können ihn rotieren oder widerrufen. Ein widerrufener oder rotierter Schlüssel funktioniert sofort nicht mehr. Ein Schlüssel handelt nur für seine Organisation: Ids einer anderen Organisation antworten mit 404, als gäbe es sie nicht.
Scopes
Jeder Schlüssel hat einen von zwei Scopes, den Sie beim Erstellen wählen:
- Lesen und schreiben (
read_write, der Standard) ruft jede Route auf. - Nur lesen (
read) ruft nur dieGET-Routen auf: ein Project, seine Fracht, einen Ladeplan oder eine Berechnung lesen und die Bibliotheken auflisten. Jede andere Route antwortet mit403,code: "FORBIDDEN"unddata.reason: "insufficient_scope", bevor etwas geändert wird.
Schlüssel, die vor den Scopes erstellt wurden, haben Lese- und Schreibzugriff. Beim Rotieren behält ein Schlüssel seinen Scope.
Ablauf
Ein Schlüssel läuft nie ab, außer Sie legen beim Erstellen einen Ablauf fest: in 30 Tagen, 90 Tagen oder einem Jahr (die API erlaubt höchstens zwei Jahre im Voraus). Ab diesem Zeitpunkt antwortet der Schlüssel wie ein widerrufener mit 401. Rotieren Sie einen Schlüssel mit Ablauf, erhält der neue Schlüssel eine neue Laufzeit gleicher Länge; so macht eine Rotation auch einen abgelaufenen Schlüssel wieder nutzbar.
Von wem der Schlüssel abhängt
Ein Schlüssel bleibt nur gültig, solange das Mitglied, das ihn erstellt hat, noch in der Organisation ist und noch Inhaber oder Admin ist, also eine Rolle hat, die API-Schlüssel verwalten darf. Verlässt dieses Mitglied die Organisation, wird es entfernt oder zu Mitglied oder Betrachter herabgestuft, antwortet jeder Schlüssel, den es erstellt hat, mit 401. Der Schlüssel wird nicht auf Nur-Lesen herabgestuft, sondern gesperrt. Ein Inhaber oder Admin erstellt dann einen neuen Schlüssel.
Ein fehlender, fehlerhafter, widerrufener, abgelaufener oder unbekannter Schlüssel, oder einer, dessen Ersteller die Bedingung nicht mehr erfüllt, antwortet mit 401, code: "UNAUTHORIZED" und dem Header WWW-Authenticate: Bearer realm="api". Die Antwort ist in jedem Fall gleich und verrät nicht, welche Prüfung fehlschlug; der Grund wird serverseitig im API-Audit-Protokoll festgehalten (siehe Audit-Protokoll).
API-Zugang gibt es nur mit Enterprise (apiAccess). Andere Pläne erhalten 403 mit code: "FORBIDDEN". Die Pläne, die heute verkauft werden, setzen dieses Flag nicht, bis der Enterprise-Katalog live ist.
Die API ist für Server-zu-Server-Aufrufe gedacht. Behalten Sie den Schlüssel auf Ihrem Server und rufen Sie die API nicht aus einem Browser auf. Cross-Origin-Anfragen aus dem Browser anderer Websites sind nicht erlaubt, und /api/v1 sendet und akzeptiert nie ein Cookie.
Was ein Schlüssel kann
| Methode | Pfad | Wirkung | Erfolg |
|---|---|---|---|
POST |
/projects |
Ein Project anlegen | 201 |
GET |
/projects/{projectId} |
Ein Project mit seinen Load-Plan-Köpfen lesen | 200 |
POST |
/projects/{projectId}/load-plans |
Einen Ladeplan anlegen | 201 |
POST |
/projects/{projectId}/cargo |
Frachtzeilen importieren | 201 |
GET |
/projects/{projectId}/cargo |
Die Frachtzeilen des Projects auflisten | 200 |
PATCH |
/load-plans/{loadPlanId}/equipment |
Der Laderaum des Ladeplans ändern | 200 |
POST |
/load-plans/{loadPlanId}/calculate |
Eine Berechnung einreihen | 202 |
GET |
/calculates/{id} |
Einen Berechnungslauf lesen | 200 |
POST |
/calculates/{id}/cancel |
Einen Berechnungslauf abbrechen | 200 |
GET |
/load-plans/{id} |
Den gespeicherten Ladeplan lesen, mit Placements | 200 |
POST |
/load-plans/{loadPlanId}/share-links |
Einen rein lesenden Freigabelink erzeugen | 201 |
GET |
/libraries/cargo |
Die Cargo Library auflisten | 200 |
GET |
/libraries/equipment |
Laderaum-Typen auflisten, inkl. Sea- und Road-Typen | 200 |
- Frachtzeilen liegen schon in Millimetern und Gramm vor. Eine Zeile kann einen
groupKeytragen: Zeilen mit demselben Schlüssel sind eine Gruppe, die als ein Block in eine Ladeeinheit geladen oder als Ganzes mit dem Grundgroup-does-not-fitnicht verladen wird. Ein Import von bis zu 5.000 Zeilen ist eine Transaktion: Er wird ganz oder gar nicht angehängt. - Eine Zeile kann eine
stop(Entladestelle) tragen, eine ganze Zahl von 1 bis 99 odernull, beim Schreiben optional. Entladestelle 1 wird zuerst entladen, und eine Zeile ohne Entladestelle wird nach allen Entladestellen entladen. Ein Projekt kannstopstragen, ein Array aus{stop, name}mit eindeutigen, aufsteigenden Ordnungszahlen, beim Schreiben optional. Die Namen sind nur Bezeichnungen. Projektdateien tragen dieselben optionalen Felder, und ältere Dateien lassen sich weiterhin importieren. - Eine Zeile kann
minSupportPermilletragen, eine ganze Zahl von 501 bis 1000 odernull, beim Schreiben optional. Es ist der Mindestanteil der Grundfläche des Stücks in Promille, der auf direkt darunterliegender Ladung aufliegen muss, wenn es nicht auf dem Boden steht.nullund weggelassen bedeuten beides 1000, volle Auflage. Bibliothekseinträge und Projektdateien tragen dasselbe optionale Feld, und ältere Dateien lassen sich weiterhin importieren. - Eine Zeile kann
frictionSurfacetragen, worauf ihre Stücke für die Ladungssicherungsprüfung stehen: eines vonwood_on_wood,planed_wood_on_wood,wood_on_steel,plastic_on_wood,plastic_on_metal,steel_on_wood,steel_on_steelundrubber_mat, odernull, beim Schreiben optional.nullund weggelassen bedeuten beides die Standard-Reibung des Ladeplans. Bibliothekseinträge und Projektdateien tragen dasselbe optionale Feld, und ältere Dateien lassen sich weiterhin importieren. - Ein Ladeplan in einer Projektdatei kann
securingtragen, die Transportabschnitte, für die er die Ladungssicherung prüft:{"legs": [...]}mit einem oder mehreren vonroad,rail,sea-a,sea-bundsea-cund einem optionalenfrictionPermillevon 1 bis 1500.nullund weggelassen bedeuten beides keine Prüfung, daher lassen sich ältere Dateien weiterhin importieren. Wurde das gespeicherte Ergebnis einer Datei gegen andere Abschnitte geprüft, wird es beim Import gegen die Abschnitte des Plans neu geprüft. - Laderaum-Ids stammen aus
GET /libraries/equipment, inklusive der eingebauten Sea- und Road-Typen.
Projects und Fracht lesen
GET /projects/{projectId} liefert die Metadaten des Projects, cargoLineCount und je Ladeplan einen Kopf, der älteste zuerst: id, name, revision, stale, solvedAt (null vor der ersten Berechnung), createdAt und updatedAt. Fracht, Laderaum und Placements sind nicht enthalten; Laderaum und gespeichertes Ergebnis eines Ladeplans liest GET /load-plans/{id}.
GET /projects/{projectId}/cargo liefert die Frachtzeilen des Projects seitenweise in Grid-Reihenfolge, also in der Reihenfolge, in der sie importiert oder in der App angeordnet wurden. Jeder Eintrag hat jedes Feld, das eine Importzeile nimmt, mit ausgefüllten Standardwerten (rotation: "free", stackable: true, fragile: false) und fehlenden Werten als null, dazu id, revision, sourceLibraryItemId (gesetzt, wenn die Zeile aus der Cargo Library stammt), createdAt und updatedAt. Um Fracht in ein anderes Project zu kopieren, lassen Sie diese zusätzlichen Felder weg und senden den Rest an POST /projects/{projectId}/cargo.
Einheiten und Formate
Längen sind ganze Millimeter (lengthMm, innerWidthMm, …), Gewichte ganze Gramm (weightG, maxPayloadG, …). Zeitpunkte sind RFC-3339-Strings in UTC, Kalenderdaten YYYY-MM-DD. Request-Bodies sind JSON mit Content-Type: application/json und höchstens 4 MB groß; ein größerer Body antwortet mit 413. Unbekannte Schlüssel im Request-Body ergeben 400. Antworten können neue Felder bekommen; ignorieren Sie Felder, die Sie nicht kennen.
Laderaum
PATCH /load-plans/{loadPlanId}/equipment führt eine Änderung mit dem Laderaum des Ladeplans zusammen:
equipmentTypeIdsist die vollständige Menge der gewählten Laderaum-Typen aus der Bibliothek. Ein weggelassener Typ wird abgewählt.maxUnitsByEquipmentTypeIdsetzt optional die Höchstzahl an Ladeeinheiten pro gewähltem Typ (nullheißt ohne Grenze). Ein gewählter Typ, den Sie weglassen, behält seine Grenze.- Laderaum ohne Bibliothekstyp (importiert, oder dessen Typ gelöscht wurde) bleibt, außer seine Id steht in
removeEquipmentIds. Eine Id, die nicht mehr am Plan hängt, wird ignoriert. - Gewählte Typen und verbleibendes Laderaum dürfen zusammen 20 Zeilen nicht überschreiten.
Senden Sie expectedRevision mit der revision Ihres letzten Lesens. Hat sich der Ladeplan inzwischen geändert, wird nichts gespeichert, und der Aufruf antwortet mit 412 und code: "PRECONDITION_FAILED"; data.conflicts nennt die Ressource mit expectedRevision und currentRevision. Lesen Sie erneut und wiederholen Sie den Aufruf. Die Antwort enthält die neue revision für Ihren nächsten Schreibaufruf.
Berechnung
Eine Berechnung nutzt denselben Optimierer wie Berechnen in der App und läuft im Hintergrund:
GET /load-plans/{id}aufrufen undrevisionmerken.POST /load-plans/{loadPlanId}/calculatemit{"expectedRevision": <revision>}senden. Gesperrte Placements bleiben immer erhalten. Hat jemand Stücke von Hand verschoben, ohne sie zu sperren, senden Sie"replaceUnlockedManual": true, damit der Lauf sie ersetzen darf; ohne das Flag antwortet der Aufruf mit409, statt die manuelle Arbeit zu überschreiben. Ein gesperrtes Placement über dem Boden muss auf anderen gesperrten Placements stehen: Sonst antwortet der Aufruf mit400und einer Meldung, die das betroffene Stück nennt, weil der Solver nie ein freies Stück unter ein gesperrtes schiebt. Sperren dürfen auch keine Gruppe aufbrechen: Eine nur teilweise gesperrte Gruppe, gesperrte Stücke einer Gruppe in zwei Ladeeinheiten oder eine Sperre im Block einer anderen Gruppe ergeben ebenfalls400mit der Gruppe oder den betroffenen Stücken. Die App sperrt und entsperrt eine Gruppe immer als Ganzes. Die Antwort ist202mit der Lauf-idundstatus: "queued".GET /calculates/{id}abfragen oder Webhooks abonnieren und auf das Ereignis warten.statuswechselt überqueuedundrunning(mitphase,processedItemsundtotalItems) zucompleted,cancelled,failedodertimed_out. Ein fehlgeschlagener Lauf liefert einenfailureCode, zum Beispielrevision_conflict, wenn sich der Ladeplan nach Ihrem Lesen geändert hat.- Ist der Lauf
completed, lesen SieGET /load-plans/{id}erneut für die Placements. Der Lauf selbst meldet nur die neuerevisionundsolvedAt.
Im gespeicherten Ergebnis listet warnings Regelverstöße, nicht geladene Ladung und den Schwerpunkt-Hinweis. Achslast-Hinweise für Straßen-Laderaum mit Achsprofil (axle-overload, axle-lift, steer-axle-underload, drive-axle-underload, gross-overload) stehen gesondert in axleWarnings; das Feld fehlt, wenn es keine gibt. Eine Entladestelle, deren Ladung unter Ladung einer späteren Entladestelle oder ohne Entladestelle steht oder vor jeder Öffnung, durch die sie hinaus könnte, wird als stop-blocked im optionalen Array stopWarnings gemeldet, neben warnings und axleWarnings. Die Liste warnings bleibt unverändert. Es ist nur eine Warnung, und ein Die Berechnung wird deswegen nie abgelehnt.
GET /load-plans/{id} liefert das securing des Plans: die Transportabschnitte, für die er die Ladungssicherung prüft, oder null für keine Prüfung. Die Abschnitte werden in der App gesetzt; die API liest sie nur. Hinweise zur Ladungssicherung (securing-unblocked und securing-tipping) stehen im optionalen Array securingWarnings des gespeicherten Ergebnisses; das Feld fehlt, wenn es keine gibt. Jeder Hinweis nennt eine Ladeeinheit, eine direction (forward, rearward oder sideways) und die zu sichernden Packstücke. Sie sind ein Hinweis und keine rechtliche Bewertung und stehen nie in warnings. Die Anleitung zur Ladungssicherung erklärt sie.
POST /calculates/{id}/cancel stoppt eine wartende oder laufende Berechnung. Ein abgebrochener Lauf schreibt keine Placements.
Pro Ladeplan läuft eine Berechnung zur Zeit: Ein zweites Einreihen, während eine wartet oder läuft, antwortet mit 409. Eine Organisation darf 10 Berechnungen gleichzeitig wartend oder laufend haben; die elfte antwortet mit 429.
Eine Berechnung unterstützt höchstens 10.000 Ladungspositionen, insgesamt 20.000 Stücke und 500 Ladeeinheiten. Ladung über einer dieser Grenzen wird mit 400 abgelehnt, bevor ein Lauf eingereiht wird; die Meldung nennt die Grenze und Ihren Wert. Die Ladeeinheit-Prüfung nutzt eine untere Schranke (Gewicht, Volumen und Bodenfläche über dem größten angebotenen Laderaum) und lehnt daher nur Ladung ab, die sicher mehr als 500 Ladeeinheiten braucht.
Webhooks
Sie müssen nicht abfragen. Eine Organisation im Enterprise-Plan kann unter Einstellungen → Webhooks HTTPS-Endpunkte registrieren und erhält einen signierten POST, wenn eine Berechnung endet: calculate.completed, calculate.failed oder calculate.cancelled. Der Body nennt Berechnung, Ladeplan und Project und enthält keine Plandaten. Nach calculate.completed rufen Sie für die Placements also weiterhin GET /load-plans/{id} auf. Die Zustellung erfolgt mindestens einmal und ohne feste Reihenfolge. Die Webhooks-Anleitung behandelt die Signaturprüfung, Wiederholungen und die Netzwerkregeln, und die Spezifikation listet die Ereignisse unter webhooks.
Freigabelinks
POST /load-plans/{loadPlanId}/share-links erzeugt einen Freigabelink, der nur das Ansehen erlaubt. Verlader-Links, deren Besucher Ladeschritte abhaken können, erstellen Sie in der App. Der Body ist optional; senden Sie {"expiresAt": "2026-12-31T23:59:59Z"} für einen Link, der abläuft, oder lassen Sie ihn weg für einen, der nie abläuft. Hat der Ladeplan noch kein gespeichertes Ergebnis, antwortet der Aufruf mit 400 und data.reason load_plan_not_calculated. Starten Sie zuerst eine Berechnung. Mit showLoadingSteps: false blenden Sie die schrittweise Beladung für Besucher aus; der Standard ist true. Das ist eine Darstellungsoption: Schrittseiten, Schrittbilder und die Spalte mit dem Ladeschritt entfallen, aber die Platzierungsliste im Bericht und das CSV behalten die Ladereihenfolge, und die Plandaten des Links enthalten weiter das vollständige Ergebnis.
token und url stehen nur in der Antwort, die den Link erzeugt hat: Gespeichert wird nur ein Hash des Tokens. Bewahren Sie beides auf, oder erzeugen Sie einen neuen Link, wenn es verloren ist.
Idempotenz
POST /projects, POST /projects/{projectId}/load-plans, POST /projects/{projectId}/cargo, POST /load-plans/{loadPlanId}/calculate und POST /load-plans/{loadPlanId}/share-links verlangen den Header Idempotency-Key: 1 bis 255 sichtbare ASCII-Zeichen ohne Leerzeichen (eine UUID passt). Ohne ihn antworten sie mit 400.
- Eine Wiederholung mit demselben Schlüssel und demselben Body innerhalb von 24 Stunden liefert die erste Antwort mit demselben Status, statt ein zweites Project, einen zweiten Import, eine zweite Berechnung oder einen zweiten Freigabelink zu schreiben.
- Derselbe Schlüssel mit einem anderen Body, oder während die erste Anfrage noch läuft, antwortet mit
409undcode: "CONFLICT". - Eine Anfrage, die fehlschlug, bevor etwas geschrieben wurde (zum Beispiel
400oder404), verbraucht den Schlüssel nicht; wiederholen Sie sie mit demselben Schlüssel. - Schlüssel gelten pro API-Schlüssel. Nach dem Rotieren beginnt der neue API-Schlüssel ohne gespeicherte Idempotency-Keys.
- Ein wiederholter Freigabelink hat
tokenundurlaufnull, weil das Token nie gespeichert wird.
PATCH für Laderaum und POST /calculates/{id}/cancel nehmen keinen Idempotency-Key: Das erste schützt expectedRevision, und zweimal abbrechen wirkt wie einmal abbrechen.
Seitenweises Lesen
GET /libraries/cargo, GET /libraries/equipment und GET /projects/{projectId}/cargo liefern eine Seite: { "items": [...], "nextCursor": "…" }. Übergeben Sie nextCursor als cursor für die nächste Seite; auf der letzten Seite ist er null. Ein cursor, der kein Eintrag der Liste ist, antwortet mit 404. Bei den Bibliotheken setzt limit die Seitengröße, 1 bis 100 (Standard 20), und query filtert nach einem Teilstring, ohne auf Groß- und Kleinschreibung zu achten. Bei Frachtzeilen ist limit 1 bis 500 (Standard 100), und totalCount zählt alle Zeilen des Projects.
Die Laderaum-Liste filtert außerdem nach mode (sea oder road) und nach ids, das auch für eine einzelne Id die Klammer-Schreibweise verlangt:
curl -sS "$ORIGIN/api/v1/libraries/equipment?ids[]=eqt_a&ids[]=eqt_b" \
-H "Authorization: Bearer $CARGO_MARSHAL_API_KEY"
Limits
| Limit | Geltung | Budget |
|---|---|---|
| Anfragen | pro Client-IP, vor der Anmeldung | 300 pro Minute |
| Anfragen | pro API-Schlüssel | 120 pro Minute |
| Berechnungen einreihen | pro API-Schlüssel | 30 pro 10 Minuten |
| Gleichzeitige Berechnungen | pro Organisation | 10 wartend oder laufend |
Eine Anfrage über einem Limit antwortet mit 429, code: "TOO_MANY_REQUESTS" und einem Retry-After-Header in Sekunden (auch in data.retryAfter, wenn das Limit ihn kennt). Warten Sie so lange, bevor Sie es erneut versuchen. Eine wiederholte Berechnung (derselbe Idempotency-Key) verbraucht das Berechnungsbudget nicht.
Die Limits pro Schlüssel fallen geschlossen aus: Ist der Limiter in Produktion nicht erreichbar, antwortet der Aufruf mit 503, statt durchgelassen zu werden. Wiederholen Sie 503 mit Backoff.
Fehler
Jeder Fehler antwortet mit demselben JSON-Body:
{
"defined": true,
"code": "BAD_REQUEST",
"status": 400,
"message": "Input validation failed",
"data": {
"reason": "invalid_input",
"issues": [
{
"path": ["body", "lines", 0, "lengthMm"],
"message": "Too small: expected number to be >=1",
"code": "too_small"
}
]
}
}
Entscheiden Sie anhand von code und, wo gesetzt, data.reason; message ist englischer Text für Menschen und kann sich ändern. defined: true heißt, der Fehler ist einer, den die Spezifikation für diese Route dokumentiert, mit data in der dokumentierten Form; defined: false ist ein unerwarteter Fehler, meist ein 500.
| Status | code |
Wann |
|---|---|---|
400 |
BAD_REQUEST |
Ungültige Eingabe (data.reason invalid_input, data.issues listet höchstens 50 fehlgeschlagene Prüfungen), Ladung, die der Solver nicht annimmt, oder ein Freigabelink auf einem nicht berechneten Ladeplan (load_plan_not_calculated) |
401 |
UNAUTHORIZED |
Fehlender, ungültiger, widerrufener oder abgelaufener API-Schlüssel, oder sein Ersteller ist nicht mehr Inhaber oder Admin |
403 |
FORBIDDEN |
Der Plan der Organisation enthält keinen API-Zugang, oder ein Schlüssel mit Nur-Lesen hat eine schreibende Route aufgerufen (insufficient_scope) |
404 |
NOT_FOUND |
Die Id gibt es in der Organisation des Schlüssels nicht, oder der Pfad ist keine Route |
405 |
— | Den Pfad gibt es für andere Methoden; der Header Allow nennt sie |
409 |
CONFLICT |
Wiederverwendeter Idempotency-Key, eine bereits laufende Berechnung oder nicht gesperrte manuelle Placements |
409 |
PLAN_LIMIT |
Ein Tariflimit für Projekte, Berechnungen oder Freigabelinks |
412 |
PRECONDITION_FAILED |
expectedRevision ist veraltet |
413 |
— | Der Body ist größer als 4 MB |
429 |
TOO_MANY_REQUESTS |
Ein Limit ist erreicht; siehe Retry-After |
503 |
SERVICE_UNAVAILABLE |
Der Limiter oder ein anderer Dienst ist nicht erreichbar; mit Backoff wiederholen |
Die Spezifikation nennt pro Route genau, welche dieser Codes sie liefern kann.
Ein Tariflimit antwortet mit 409, code: "PLAN_LIMIT" und data, das das Limit nennt:
{
"reason": "plan-limit",
"resource": "solves",
"limit": 10,
"planName": "Free"
}
resource ist projects, solves oder share-links.
Jede Antwort trägt einen Header x-request-id. Nennen Sie ihn, wenn Sie den Support kontaktieren; Sie können auch eine eigene x-request-id senden, die dann übernommen wird.
Audit-Protokoll
Der Server legt eine API-Audit-Zeile (Schlüssel, Operation, Status, Ressourcen-Id) an für:
- jeden schreibenden Aufruf, auch eine Wiederholung mit demselben
Idempotency-Key, ob er gelingt oder scheitert; - jeden lesenden Aufruf, der in der Operation scheitert, zum Beispiel ein
404für die Id einer anderen Organisation; - jede Ablehnung eines bekannten Schlüssels: Rate-Limit (
429), Nur-Lesen-Scope (403), Plan ohne API-Zugang (403) sowie ein abgelaufener Schlüssel oder einer, dessen Ersteller die Bedingung nicht mehr erfüllt (401).
Erfolgreiche Lesezugriffe (GET-Routen mit 200) werden nicht festgehalten: Sie ändern nichts, und Integrationen fragen sie regelmäßig ab. Ebenfalls nicht festgehalten werden Anfragen, die am Eingabeschema scheitern (400 mit invalid_input), unbekannte oder widerrufene Schlüssel und Anfragen, die das Limit pro IP ablehnt.
Was ein Schlüssel nicht kann
Ein Schlüssel kann keine Placements und keinen Solve-Snapshot senden: Der Body der Berechnung nimmt nur die erwartete Revision und das Flag für manuelle Placements, und Placements werden immer auf dem Server berechnet. Admin, Abrechnung, Chat, Anmeldung und Dateispeicher bleiben außerhalb dieser API.
Versionierung und Abkündigung
/api/v1 ist stabil. Innerhalb von v1 gibt es nur additive Änderungen: neue Routen, neue optionale Eingabefelder, neue Antwortfelder, neue Werte für code oder data.reason bei einem bestehenden Status. Bauen Sie Clients so, dass sie unbekannte Antwortfelder ignorieren.
Eine inkompatible Änderung (eine Route oder ein Feld entfernen oder umbenennen, eine optionale Eingabe zur Pflicht machen, einen Typ oder einen Erfolgsstatus ändern) erscheint unter einer neuen Version, /api/v2, und v1 funktioniert daneben weiter. Jede Änderung der Spezifikation wird vor der Auslieferung auf inkompatible Änderungen geprüft.
Bevor eine Route oder ein Feld entfernt wird, ist sie in der Spezifikation mit deprecated: true markiert. Jede Antwort einer abgekündigten Route, ob erfolgreich oder nicht, trägt:
Deprecation:trueoder das Datum der Abkündigung in der Form@<Unix-Sekunden>nach RFC 9745, zum BeispielDeprecation: @1790812800.Sunset: das Datum der Entfernung als HTTP-Datum (RFC 8594), zum BeispielSunset: Thu, 01 Apr 2027 00:00:00 GMT, sobald es feststeht.Link: <…>; rel="deprecation": die Seite, die die Umstellung erklärt, sobald sie veröffentlicht ist.
Das Sunset-Datum liegt mindestens 6 Monate nach der Ankündigung. Protokollieren Sie diese Header in Ihrem Client, damit eine Abkündigung nicht unbemerkt bleibt. Heute ist keine v1-Route abgekündigt.
Beispiel
curl -sS -X POST "$ORIGIN/api/v1/projects" \
-H "Authorization: Bearer $CARGO_MARSHAL_API_KEY" \
-H "Idempotency-Key: project-4401" \
-H "Content-Type: application/json" \
-d '{"name":"Hamburg 40HC"}'
Ersetzen Sie $ORIGIN durch die App-URL. Der Aufruf antwortet mit 201 und dem neuen Project.