Bestands- und Lager-API
Mit der Bestands- und Lager-API liest und ändert Ihr eigenes System Ihr QrX-Lager: Bestände, Artikel, Lagerplätze, Bewegungen, Wareneingänge, Bestellungen, Picklisten, Inventuren, Ladungsträger und Teamaufgaben. Dieser Artikel richtet sich an Entwickler. Die Basis-URL ist https://api.qr-x.net, und jeder Aufruf benötigt Authorization: Bearer <accessToken>; zum Token siehe "Schnellstart für Entwickler: QrX Public API und Webhooks". Die vollständige Referenz finden Sie unter qrx.eu/api. Es werden nie Preise, Kosten oder Bestandswerte zurückgegeben.
Zugriff und Scopes
Bestände, Artikel, Lagerplätze, Bewegungen, Inventuren und Ladungsträger brauchen
stock.read; Artikel und Lagerplätze anlegen oder ändern und eine Korrektur buchen brauchenstock.write. Wareneingänge braucheninbound.readundinbound.write. Bestellungen brauchenpurchasing.readundpurchasing.write. Picklisten brauchenfulfilment.readund Teamaufgabentasks.read.Ein eingeschränkter Schlüssel erhält die neuen Bereiche nie automatisch. Haken Sie unter API-Zugriff Einkauf, Fulfillment oder Aufgaben an, wenn der Schlüssel sie braucht. Wareneingangspositionen zeigen
unitPriceundcurrencynur, wenn der Schlüssel auch Bestellungen lesen darf.Ein API-Schlüssel, der nicht eingeschränkt ist, hat vollen Zugriff und kann die Bestands-API sofort nutzen.
Um einen Schlüssel einzuschränken, öffnen Sie Settings > Business > Merchant Channels, öffnen den Vertriebskanal, Registerkarte Settings, Block API-Zugriff, und haken Bestände, Artikel, Lagerplätze, Bewegungen, Inventuren und Ladungsträger lesen und Bestand anpassen sowie Artikel und Lagerplätze anlegen oder ändern nach Bedarf an. Siehe "Einen API-Schlüssel einschränken (API-Zugriff)".
In Ihrem Konto muss der QrX-Lagerbestand eingeschaltet sein. Ohne ihn antwortet die API mit 403
ACCESS_DENIED.
GET /api/v1/stock/levels
Eine Zeile pro Bestandsartikel und Lager. Query: stockItemId, sku, warehouseId, locationId, updatedSince (ISO 8601), cursor, limit (1 bis 200, Standard 50) und scope.
{
"items": [{
"stockItemId": 345, "sku": "TSHIRT-M", "ean": "8712345678906",
"ownerCustomerId": null, "partnerCustomerId": null,
"warehouseId": 1, "warehouseCode": "MAIN",
"onHand": 42, "sellable": 40, "blocked": 2, "reserved": 5,
"incoming": 0, "backorder": 0, "available": 35,
"locationQuantity": null,
"lastSequence": 98231, "updatedAt": "2026-10-11T09:12:03Z"
}],
"nextCursor": "1-345"
}
reservedist alles, was offene Bestellungen halten.availableistsellableminusreserved.lastSequenceist die Nummer der letzten Bestandsbewegung dieses Artikels in diesem Lager. Es ist dieselbe Nummer wiesequenceim Webhookstock/adjusted.skumuss exakt übereinstimmen; Groß- und Kleinschreibung sowie Leerzeichen am Rand werden ignoriert.Mit
locationIderhalten Sie nur Artikel, die an diesem Lagerplatz Bestand haben, undlocationQuantityenthält die Einheiten dort.
GET /api/v1/stock/items
Ihre Bestandsartikel, die neuesten zuerst. Query: sku, ean, updatedSince, cursor, limit (1 bis 200, Standard 50) und scope.
{
"items": [{
"id": 345, "sku": "TSHIRT-M", "name": "T-shirt M", "ean": "8712345678906",
"unit": "piece", "kind": "simple", "trackingMode": "none", "isActive": true,
"ownerCustomerId": null, "partnerCustomerId": null, "weightG": 180,
"updatedAt": "2026-10-01T08:00:00Z"
}],
"nextCursor": 344
}
GET /api/v1/stock/locations
Die Lagerplätze, die Bestand führen können, die neuesten zuerst. Query: warehouseId, cursor, limit (1 bis 200, Standard 50).
{
"items": [{ "id": 77, "warehouseId": 1, "warehouseCode": "MAIN", "code": "A-01-02",
"kind": "bin", "zone": "A", "isActive": true }],
"nextCursor": 76
}
POST /api/v1/stock/adjust
Bucht eine Bestandskorrektur. Der Header Idempotency-Key ist erforderlich.
POST /api/v1/stock/adjust
Idempotency-Key: erp-count-2026-10-11-0001{ "stockItemId": 345, "sku": null, "warehouseId": null, "locationId": 77, "delta": -3,
"reasonCode": "correction", "note": "Cycle count by ERP", "lotCode": null, "expiryDate": null }
Geben Sie
stockItemIdoderskuan. Es muss genau ein Artikel passen.Geben Sie
locationIdan. Ein Konto ohne Lagerplätze darf stattdessenwarehouseIdangeben, oder nichts für das Standardlager.deltaist die Änderung in Einheiten: positiv bucht zu, negativ bucht ab. Der Wert darf nicht 0 sein.reasonCodeist erforderlich:correction,found,damaged,expired,defective,lost,theft,sampleoderother.Geben Sie für einen Artikel mit Chargen
lotCodeund, wenn der Artikel es benötigt,expiryDatean.
Die Antwort enthält den neuen Stand des Artikels in diesem Lager:
{ "movementId": 98231, "stockItemId": 345, "warehouseId": 1, "locationId": 77, "delta": -3,
"onHand": 42, "sellable": 40, "available": 35, "sequence": 98231, "replayed": false }
Lagerressourcen
Alle Listen verwenden cursor und limit (1 bis 100, Standard 50) und antworten mit items und nextCursor, die neuesten zuerst. Diese Ressourcen sind nur Ihre eigenen Lagerdaten: scope=partner antwortet mit 422. Alle Felder von Anfrage und Antwort stehen in der Referenz unter qrx.eu/api.
Wareneingänge:
GET /api/v1/receipts(Filterstate,warehouseId,q),GET /api/v1/receipts/{id},POST /api/v1/receipts(mitannounce: truewird der Wareneingang angekündigt),PATCH /api/v1/receipts/{id},POST .../{id}/lines,POST .../{id}/completeundPOST .../{id}/cancel.Bestellungen:
GET /api/v1/purchase-orders,GET /api/v1/purchase-orders/{id},POST /api/v1/purchase-orders(ein Entwurf),PATCH .../{id},POST .../{id}/lines,POST .../{id}/send,POST .../{id}/closeundPOST .../{id}/cancel. Senden funktioniert genau wie in PortalX: Mitemail: truesendet QrX das PDF an den Lieferanten (oder anto), höchstens 5-mal pro Bestellung und 30-mal pro Konto und Stunde (429RATE_LIMIT_EXCEEDED).Lagerartikel und Lagerplätze:
POSTundPATCH /api/v1/stock/itemsund/api/v1/stock/locations. Lagerplätze erfordern Full WMS mit Lagerfächern. Die Zeilen vonGET itemsundGET locationshaben jetztversion.Lesen:
GET /api/v1/stock/movements,GET /api/v1/picklists,GET /api/v1/counts(mit/{id}und/{id}/lines),GET /api/v1/containersundGET /api/v1/tasks(mit/{id}). Teamaufgaben sind nur lesbar.Eine Änderung eines bestehenden Datensatzes braucht die
version, die Sie zuletzt gelesen haben. Hat jemand den Datensatz inzwischen geändert, erhalten Sie 409: Lesen Sie ihn neu und versuchen Sie es erneut.Lager (Scope
stock.read, Vollständiges WMS):GET /api/v1/warehousesmit Code, Name, Standard, Zeitzone, Adresse, Kontakt, Anlieferhinweisen, Laderampen und GLN;GET /api/v1/warehouses/{id},.../{id}/hours(Wareneingangs- und Versandzeiten pro Wochentag) und.../{id}/closures(mitfromundcursor).Umlagerungen (Scope
stock.read, Vollständiges WMS mit mehreren Lagern und Umlagerungen):GET /api/v1/transfers(Filterstate,warehouseId,direction) undGET /api/v1/transfers/{id}mit den Positionen und denshipping-Daten. Nur lesend.Bestellungen: Anlegen und
PATCHakzeptieren die Kopffelderreference,supplierReference,buyerUserId,internalNote,incoterm,incotermPlace,paymentTermsDays,shippingCost,shippingVatRate,pricesIncludeVat,deliveryAddressundpartialDeliveryAllowed, und Positionen akzeptierendiscountPct,vatRate,note,confirmedQtyundconfirmedOn. Bestellungen liefern die von QrX berechneten Summen (netto, MwSt. pro Satz, brutto). Die Liste filtert nachreference,expectedFromundexpectedTo. Die Konditionen sind nach dem Senden der Bestellung festgeschrieben.Wareneingänge: Anlegen und
PATCHakzeptierensupplierId, um einen Wareneingang mit einem Lieferanten zu verknüpfen; Zeilen liefern es zurück.Lagerartikel und Lagerplätze: Schreibzugriffe auf Lagerplätze akzeptieren
zoneoderzoneIdund die Felder für Maße und Kapazität; Schreibzugriffe auf Artikel akzeptierenstorage,dangerousGoods,imageUrlundabcClassOverride.POST /api/v1/stock/adjustakzeptiert Ihre eigenen Grundcodes.
Idempotency-Key
Senden Sie pro Korrektur einen eigenen eindeutigen Text. Wiederholen Sie dieselbe Anfrage mit demselben Schlüssel, erhalten Sie die erste Antwort erneut mit
replayed: true, und nichts wird doppelt gebucht.Derselbe Schlüssel mit einem anderen Body wird mit 409
DUPLICATE_IDEMPOTENCY_KEYabgelehnt.Ein Schlüssel darf nicht mit einem QrX-Systempräfix wie
mcp-beginnen und nicht auf einen Doppelpunkt gefolgt von Ziffern enden (422).Jeder POST und PATCH der Lagerressourcen braucht den Header
Idempotency-Key(1 bis 140 Zeichen). Derselbe Schlüssel mit demselben Body auf derselben Route liefert die erste Antwort erneut, mit dem HeaderIdempotent-Replayed: true. Ein wiederholtes Anlegen eines Wareneingangs oder einer Bestellung liefert den Datensatz, wie er jetzt ist.Antworten werden 30 Tage aufbewahrt. Ein fehlgeschlagener Aufruf (4xx oder 5xx) wird nicht aufbewahrt, Sie dürfen denselben Schlüssel also erneut senden.
Solange der erste Aufruf mit einem Schlüssel noch läuft, erhalten Sie 409
CONCURRENCY_CONFLICTmitRetry-After. Ein Aufruf, der mittendrin abgebrochen ist, gibt seinen Schlüssel nach 15 Minuten frei.Das Senden einer Bestellung mit
email: truemailt den Lieferanten höchstens einmal pro Schlüssel. Schlägt ein Aufruf fehl, nachdem die Bestellung gesendet wurde, aber vor der E-Mail, folgt für diesen Schlüssel keine E-Mail: Prüfen Sie den E-Mail-Verlauf der Bestellung in PortalX und senden Sie mit einem neuen Schlüssel erneut.
Cursor und updatedSince
Jede Liste gibt
itemsundnextCursorzurück. Senden SienextCursoralscursorfür die nächste Seite. Null bedeutet das Ende. Es gibt keine Gesamtzahl.Behandeln Sie einen Cursor als undurchsichtigen Wert.
Mit
updatedSinceerhalten Sie nur Zeilen, die zu diesem Zeitpunkt oder danach geändert wurden. Der Server betrachtet bis zu 1.000 Zeilen pro Aufruf, eine Seite kann also weniger Zeilen alslimitenthalten, sogar keine, währendnextCursorgesetzt ist. Rufen Sie weiter auf, bisnextCursornull ist.
Bestand bei einem Fulfillment-Partner: scope=partner
Lagert ein Fulfillment-Partner Ihren Bestand, fügen Sie scope=partner zu GET levels und GET items hinzu, um Ihren eigenen Bestand bei Ihren Partnern zu lesen. Ohne erhalten Sie den Standard, scope=warehouse: den Bestand in Ihren eigenen Lagern.
Jede Zeile hat
partnerCustomerId(das Partnerlager) und Ihre eigene Id inownerCustomerId.Verwenden Sie
partnerCustomerIdin der Query, um einen Partner zu behalten, undwarehouseIdfür eines seiner Lager.Lagerplätze werden nie zurückgegeben:
locationId,GET locationsundPOST adjustantworten in diesem Scope mit 422.Sie benötigen mindestens einen Partner mit aktivem Zugriff; in Ihrem eigenen Konto muss der Lagerbestand nicht eingeschaltet sein.
Fehlercodes
401
UNAUTHORIZED: kein gültiges Zugriffstoken.403
STOCK_SCOPE_MISSING: Der Schlüssel ist eingeschränkt und hatstock.readoderstock.writenicht.403
ACCESS_DENIED: Der Lagerbestand ist für das Konto nicht eingeschaltet, oder, mitscope=partner, kein Partner hat aktiven Zugriff.404
STOCK_NOT_FOUND: Der Artikel, das Lager oder der Lagerplatz gehört nicht Ihnen.400
IDEMPOTENCY_KEY_REQUIRED: ein POST ohne den Header.422
VALIDATION_FAILED: ungültige Eingabe, zum Beispiel delta 0, ein unbekannter Grundcode, ein ungültiger Cursor oder mehr als 50 Artikel mit derselben SKU oder EAN (nachstockItemIdfiltern).409
DUPLICATE_IDEMPOTENCY_KEY: derselbe Schlüssel mit einem anderen Body.409
STOCK_CONFLICT: nicht genug Bestand, Bestand, der einer Pickliste zugeteilt ist, eine SKU, die zu mehreren Artikeln passt, oder ein inaktiver Artikel.409
CONCURRENCY_CONFLICT: Senden Sie dieselbe Anfrage mit demselben Schlüssel erneut.429: zu viele Anfragen; warten Sie
Retry-Afterab.403
INBOUND_SCOPE_MISSING,PURCHASING_SCOPE_MISSING,FULFILMENT_SCOPE_MISSINGoderTASKS_SCOPE_MISSING: Der Schlüssel ist eingeschränkt und es fehlt dieser Bereich.404
INBOUND_NOT_FOUND,PURCHASE_ORDER_NOT_FOUNDoderNOT_FOUND: Der Datensatz gehört nicht Ihnen.409
INBOUND_CONFLICToderPURCHASING_CONFLICT: Version oder Status erlauben die Änderung nicht.429
RATE_LIMIT_EXCEEDED: zu viele E-Mails an den Lieferanten für eine Bestellung.400
ZONE_UNKNOWN: Die Zone ist keine aktive Zone dieses Lagers. 400DG_CLASS_UNKNOWN: Die Gefahrgutklasse ist keine sichtbare Klasse Ihres Kontos. Ein Grund, der Fotos verlangt, kann über die API nicht verwendet werden.
Wann Sie unser Support-Team kontaktieren sollten
Kontaktieren Sie den QrX-Support, wenn die API ACCESS_DENIED antwortet, obwohl der Lagerbestand eingeschaltet ist, oder wenn ein Stand von PortalX abweicht. Nennen Sie die requestId der Antwort, die SKU und den Zeitpunkt. Senden Sie nie den API-Schlüssel oder das Token mit.
