Bestellungen über die Schnittstelle abholen, ohne sich selbst ins Gehege zu kommen
GET /orders reserviert nichts. Es gibt jede Bestellung an jeden Abrufer heraus, den Sie laufen lassen. Es gibt einen Endpunkt, der sie tatsächlich beansprucht, eine Sperrfrist, die Sie selbst setzen müssen, und drei Grenzen, die nirgends dokumentiert sind.
Sarah JohnsonVorweg eine Klärung, weil auf dieser Website zwei Schnittstellen liegen und sie regelmäßig verwechselt werden. Die eine hat einen einzigen Zugangspunkt, dem eine Aktion mitgegeben wird, und dient dem Einkauf: Kategorien lesen, bestellen, Status abfragen, stornieren. Die andere ist die hier beschriebene, sie liegt unter /api/admin/v2, sie ist im Format eines verbreiteten Panels gehalten, und sie dient der Belieferung. Wenn Sie Bestellungen erfüllen, ist die zweite gemeint.
Die erste Entscheidung darin ist, womit Sie Arbeit einsammeln, und genau diese Entscheidung fällt in den meisten Anbindungen falsch aus.
Lesen ist nicht Beanspruchen
GET /orders ist eine Abfrage. Sie liefert passende Bestellungen an jeden zurück, der fragt, und ändert nichts. Lassen Sie zwei Arbeiter laufen, oder einen Arbeiter mit einem Wiederholungsversuch, bekommen beide dieselbe Bestellung und beide versuchen zu liefern.
Der Endpunkt, der Arbeit beansprucht, ist POST /orders-pull. Er sucht Ihre offenen manuellen Bestellungen heraus, setzt jede einzelne per Vergleich-und-Setzen von „pending" auf „processing" und gibt nur die zurück, deren Umschaltung tatsächlich gegriffen hat. Fragt ein zweiter Arbeiter eine Millisekunde später, schlägt dessen Vergleich fehl und die Bestellung ist in seiner Antwort schlicht nicht enthalten.
Die Schleife in der richtigen Reihenfolge
- Beanspruchen.
POST /orders-pull. Im Rumpf optionallimit, Vorgabe 100, hart gedeckelt bei 500. Älteste Bestellung zuerst. - Sperren, falls Ihr Arbeiter langsam ist.
PATCH /orders/{id}/last-process-timeohne Rumpf setzt den Zeitstempel auf jetzt und blendet die Bestellung dreißig Minuten lang aus Ihrer eigenen Abfrage aus. - Liefern.
POST /orders-updatemit den Zugangsdatenzeilen, oderPOST /orders/{id}/accounts-bulkfür alles Größere, was einen Auftragsschlüssel zum Nachfragen zurückgibt. - Abschließen. Derselbe Aufruf trägt
status: "completed", oder"partial", wenn Sie nur einen Teil erfüllt haben.
Die Anmeldung erfolgt über einen Kopfzeileneintrag an jedem Aufruf, und es werden zwei Schreibweisen akzeptiert:
curl -X POST "https://api.hstockplus.com/api/admin/v2/orders-pull" \
-H "X-Api-Key: IHR_API_SCHLUESSEL" \
-H "Content-Type: application/json" \
-d '{"limit": 50}'
# gleichwertig
curl -X POST "https://api.hstockplus.com/api/admin/v2/orders-pull" \
-H "Authorization: Bearer IHR_API_SCHLUESSEL" \
-H "Content-Type: application/json" \
-d '{"limit": 50}'
Den Schlüssel erzeugen Sie in Ihrer Verkäuferoberfläche unter den API-Einstellungen. Eine fehlende Kopfzeile ergibt API_KEY_REQUIRED, ein falscher Schlüssel INVALID_API_KEY. Das sind zwei verschiedene Codes und zwei verschiedene Fehler in Ihrem Programm.
Die dreißig Minuten sind eine Sperrfrist, und niemand setzt sie außer Ihnen
Beide abfragenden Endpunkte überspringen jede Bestellung, deren lastProcessTime innerhalb der letzten dreißig Minuten liegt. Das klingt nach einer eingebauten Doppelverarbeitungssperre und ist keine, denn kein Endpunkt schreibt dieses Feld. Geschrieben wird es ausschließlich von Ihnen, über PATCH /orders/{id}/last-process-time.
Es ist also eine freiwillige Sperre. Setzen Sie sie beim Aufnehmen einer Bestellung, verschwindet diese für eine halbe Stunde aus Ihrer nächsten Abfrage, was Sie genau dann wollen, wenn die Lieferung dauert und Ihr Abrufer im Minutentakt läuft. Ein ausdrücklicher Zeitstempel setzt eine andere Frist, null gibt sofort frei. Wer den Endpunkt gar nicht benutzt, für den greift die Frist nie.
Gegen doppeltes Beanspruchen schützt Sie bereits orders-pull über die Statusumschaltung. Die Sperrfrist deckt den zweiten Fehlerfall ab: Ihr Arbeiter hat die Bestellung, arbeitet noch, und soll sie in der Zwischenzeit nicht erneut sehen.
Zwei Voreinstellungen beim Lesen, die überraschen
GET /orders bleibt der richtige Endpunkt für Abgleich, Nacherfassung und Auswertungen. Zwei seiner Vorgaben sollten Sie kennen, bevor Sie darauf aufbauen.
- Der Zahlungsfilter hat zwei Werte, nicht einen. Ohne Parameter
paymentStatusbekommen Sie Bestellungen mit dem Zustandcompletedoderpartial. „Partial" heißt teilweise erstattet, und solche Bestellungen sind weiterhin offene Arbeit. Der Parameter selbst nimmt eine kommagetrennte Liste aus pending, completed, failed, refunded, processing und partial. - Der Produkttyp ist freiwillig und mehrwertig. Er ist für manuelle Bestellungen nicht erforderlich. Zulässig sind
manual,inventoryundauto, kommagetrennt, also istproductType=manual,autogültig.
Der Bestellstatusfilter kennt pending, processing, completed, refunded und error. partial gehört nicht dazu, das ist ein Zahlungszustand. Weitere Filter: entityType als product oder smm_service, subCategory über den Namen, createdFrom und createdTo als ISO-Zeitpunkte, limit bis 500 und offset.
curl -X GET "https://api.hstockplus.com/api/admin/v2/orders\
?status=pending,processing&productType=manual&paymentStatus=completed,partial&limit=50" \
-H "X-Api-Key: IHR_API_SCHLUESSEL"
Was mit den gesendeten Zugangsdaten geschieht
Hier entstehen die meisten Rückfragen zur Schnittstelle, weil vor dem Speichern drei Umformungen laufen und keine davon in der Antwort sichtbar ist.
- Jedes Element wird an Zeilenumbrüchen zerlegt. Ein einzelner Eintrag im Feld darf eine ganze Datei enthalten. Leerzeilen und umgebende Leerzeichen fallen weg. Am senkrechten Strich wird ausdrücklich nicht getrennt, weil der Teil eines Zugangsdatenformats ist.
- Wiederholungen werden verworfen, ohne Rücksicht auf Groß- und Kleinschreibung. Innerhalb der Sendung und gegen alles, was auf dieser Bestellung bereits geliefert wurde. Dieselbe Sendung nach einer Zeitüberschreitung erneut abzuschicken ist deshalb gefahrlos.
- Zeilen über der Bestellmenge hinaus werden stillschweigend verworfen. Die Sendung wird auf die verbleibenden Plätze gekürzt. Es gibt keinen Fehler, senden Sie also die richtige Anzahl.
Was in einer Zeile steht, bleibt vollständig Ihnen überlassen. Die Plattform speichert sie als eine einzige undurchsichtige Zeichenkette und wertet sie nie aus: ein Paar mit Doppelpunkt, ein Dreier mit senkrechten Strichen samt Schlüssel für die zweite Stufe, ein Token, ein Sitzungsabzug, alles ist bloß Text. Was Ihre Angebotsbeschreibung zusagt, ist die Vereinbarung, die der Käufer erwartet, und niemand setzt sie für Sie durch.
Weil Wiederholungen gegen frühere Lieferungen verworfen und nicht abgelehnt werden, ist die Teillieferung über mehrere Aufrufe ein vorgesehener Weg. Senden Sie, was Sie haben, setzen Sie partial, senden Sie den Rest später und setzen Sie dann completed.
Drei Grenzen, alle mit 429, und alle mit einer Wartezeit im Rumpf
orders-update trägt einen Mindestabstand je Schlüssel, in der Vorgabe 200 Millisekunden, und eine Obergrenze von zwei gleichzeitigen Anfragen je Benutzer. Dazu kommt eine Sperre je Bestellung. Alle drei antworten mit HTTP 429 und mit einer maschinenlesbaren Wartezeit:
{ "error": "RATE_LIMIT", "message": "Too many order update requests",
"retry_after_ms": 137 }
{ "error": "CONCURRENCY_LIMIT", "message": "Too many concurrent sync requests",
"retry_after_ms": 5000 }
{ "error": "ORDER_DELIVERY_BUSY", ... }
Lesen Sie retry_after_ms und schlafen Sie genau so lange. Eine feste Wartezeit ist entweder zu langsam für den Fall mit 200 Millisekunden oder zu schnell für den mit fünf Sekunden. Bei ORDER_DELIVERY_BUSY rasen zwei Lieferungen auf derselben Bestellung; richtig ist ein kurzer erneuter Versuch mit derselben Sendung, nicht ein Nachschieben anderer Zugangsdaten.
Fehlercodes, die verschieden behandelt gehören
API_KEY_REQUIREDgegenINVALID_API_KEY: keine Kopfzeile gegenüber einer Kopfzeile, die nicht erkannt wird.ORDER_NOT_FOUND: die Kennung liegt nicht im Zwischenspeicher. Bei einer eben erst erzeugten automatischen Bestellung kann das kurzzeitig auftreten, ein 404 Sekunden nach der Anlage ist also nicht zwingend endgültig.ACCESS_DENIED: die Bestellung enthält keine Position, die Ihnen gehört.PAYMENT_NOT_COMPLETED: unbezahlt oder vollständig erstattet. Hier können Sie nicht liefern, und ein erneuter Versuch ist sinnlos.INVALID_ACCOUNTSmit der Meldung „No valid accounts provided": das Feld hat sich zu nichts aufgelöst. Meist eine leere Zeichenkette oder ein Feld ohne Zeichenketten.RATE_LIMIT,CONCURRENCY_LIMIT,ORDER_DELIVERY_BUSY: warten und dieselbe Anfrage unverändert wiederholen.
Zwei Felder für Ihre eigene Buchführung
orders-update nimmt external_id für Ihre interne Bestellnummer entgegen und akzeptiert supplierOrderId als gleichbedeutend, falls Ihr Panel diese Form bereits sendet. Dazu kommt external_price, eine Zahl für das, was die Bestellung Sie vorgelagert gekostet hat. Sie wird zur Ablage gespeichert und rührt die Summen der Plattform nicht an. null oder eine leere Zeichenkette lassen den vorhandenen Wert stehen, wiederholte Aktualisierungen löschen ihn also nicht.
„Manuell" ist keine Angabe zur Geschwindigkeit
Der Produkttyp „manual" beschreibt, wer die Ware hochlädt, nicht wie lange es dauert. Über alle 6.651 abgeschlossenen manuellen Produktbestellungen der Website liegt die mittlere Zeit von der Zahlung bis zum Abschluss unter dreißig Sekunden. Gut drei Viertel sind binnen zehn Minuten fertig, und etwa jede vierzigste braucht länger als einen Tag.
Bestandsbestellungen sind praktisch verzögerungsfrei, weil die Zeilen bereits vorliegen. Automatische liegen dazwischen. Dass „manuell" fast ebenso schnell aussieht, liegt genau daran, dass die Anbieter mit Volumen auf diesem Typ diese Schnittstelle im kurzen Takt abfragen, statt auf eine Oberfläche zu schauen. Wenn Ihre Anbindung Minuten hinzufügt, sind Sie der langsame Ausläufer und nicht der Normalfall.
Eine Frist, falls Sie Reichweitendienste statt Konten liefern: Eine solche Bestellung trägt genau drei Tage ab Lieferung, unabhängig davon, was im Angebot steht. Kontenangebote tragen stattdessen die vom Verkäufer je Angebot gesetzte Garantie, und auch die läuft ab der Lieferung, nicht ab der Zahlung. Eine Bestellung, die einen Tag in Bearbeitung stand, hat davon also nichts verloren.
Ein Arbeiter, der sich benimmt
const BASE = 'https://api.hstockplus.com/api/admin/v2';
const HEAD = { 'X-Api-Key': process.env.API_KEY, 'Content-Type': 'application/json' };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function call(method, path, body) {
const res = await fetch(BASE + path, {
method,
headers: HEAD,
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json().catch(() => ({}));
if (res.status === 429) {
await sleep(json.retry_after_ms ?? 1000);
return call(method, path, body);
}
if (!res.ok) throw Object.assign(new Error(json.message || res.status), { code: json.error });
return json;
}
async function tick() {
const { orders = [] } = await call('POST', '/orders-pull', { limit: 50 });
for (const order of orders) {
// Die Bestellung steht bereits auf processing und gehoert Ihnen.
// Sperrfrist setzen, falls die Lieferung dauert:
await call('PATCH', '/orders/' + order.id + '/last-process-time', {});
const accounts = await prepareCredentials(order); // Ihr System
await call('POST', '/orders-update', {
order: order.id,
status: accounts.length >= order.quantity ? 'completed' : 'partial',
accounts,
supplierOrderId: 'SUP-' + order.id,
});
}
}
Drei Dinge macht diese Schleife anders als die verbreitete Form: Sie beansprucht, statt zu lesen. Sie hält sich an die vom Server genannte Wartezeit, statt eine zu raten. Und sie meldet partial ehrlich, statt eine Bestellung abzuschließen, die sie nicht füllen konnte.
Ob ein Angebot überhaupt manuell, aus Bestand oder automatisch sein sollte, ist eine Frage davor und steht im Leitfaden zur Produktverwaltung. Was die einkaufende Schnittstelle kann und was die Formatkompatibilität wirklich abdeckt, steht unter Aufbau der Plattform. Wenn Sie Reichweitendienste selbst anlegen wollen, siehe Reichweitendienst von Hand anlegen.



