Voorraad- en magazijn-API
Met de Voorraad- en magazijn-API leest en wijzigt uw eigen systeem uw QrX-magazijn: voorraadniveaus, artikelen, locaties, mutaties, ontvangsten, inkooporders, picklijsten, tellingen, containers en teamtaken. Dit artikel is voor ontwikkelaars. De basis-URL is https://api.qr-x.net en elke aanroep heeft Authorization: Bearer <accessToken> nodig; zie "Snelstart voor ontwikkelaars: QrX Public API en webhooks" voor het token. De volledige referentie staat op qrx.eu/api. Er wordt nooit een prijs, kostprijs of voorraadwaarde teruggegeven.
Toegang en scopes
Voorraadniveaus, artikelen, locaties, mutaties, tellingen en containers vereisen
stock.read; artikelen en locaties aanmaken of wijzigen en een correctie boeken vereisenstock.write. Ontvangsten vereiseninbound.readeninbound.write. Inkooporders vereisenpurchasing.readenpurchasing.write. Picklijsten vereisenfulfilment.readen teamtakentasks.read.Een beperkte sleutel krijgt de nieuwe onderdelen nooit vanzelf. Vink Inkoop, Fulfilment of Taken aan onder API-toegang als de sleutel ze nodig heeft. Ontvangstregels tonen
unitPriceencurrencyalleen als de sleutel ook inkooporders mag lezen.Een API-sleutel die niet is beperkt heeft volledige toegang en kan de Voorraad- en magazijn-API dus direct gebruiken.
Om een sleutel te beperken opent u Settings > Business > Merchant Channels, opent u het verkoopkanaal, tabblad Settings, blok API-toegang, en vinkt u Voorraadniveaus, artikelen, locaties, mutaties, tellingen en containers lezen en Voorraad aanpassen en artikelen en locaties aanmaken of wijzigen aan waar nodig. Zie "Een API-sleutel beperken (API-toegang)".
Op uw account moet de QrX-magazijnvoorraad aan staan. Zonder antwoordt de API met 403
ACCESS_DENIED.
GET /api/v1/stock/levels
Eén rij per voorraadartikel en magazijn. Query: stockItemId, sku, warehouseId, locationId, updatedSince (ISO 8601), cursor, limit (1 tot 200, standaard 50) en 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"
}
reservedis alles wat open orders vasthouden.availableissellableminreserved.lastSequenceis het nummer van de laatste voorraadbeweging van dat artikel in dat magazijn. Het is hetzelfde nummer alssequencein de webhookstock/adjusted.skumoet exact overeenkomen; hoofdletters, kleine letters en spaties aan de randen worden genegeerd.Met
locationIdkrijgt u alleen artikelen die voorraad op die locatie hebben, enlocationQuantitybevat de stuks daar.
GET /api/v1/stock/items
Uw voorraadartikelen, de nieuwste eerst. Query: sku, ean, updatedSince, cursor, limit (1 tot 200, standaard 50) en 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
De locaties die voorraad kunnen bevatten, de nieuwste eerst. Query: warehouseId, cursor, limit (1 tot 200, standaard 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
Boekt één voorraadcorrectie. De header Idempotency-Key is verplicht.
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 }
Geef
stockItemIdofsku. Er moet precies één artikel overeenkomen.Geef
locationId. Een account zonder locaties mag in plaats daarvanwarehouseIdgeven, of niets voor het standaardmagazijn.deltais de wijziging in stuks: positief telt bij, negatief trekt af. Het mag niet 0 zijn.reasonCodeis verplicht:correction,found,damaged,expired,defective,lost,theft,sampleofother.Geef voor een artikel met lots
lotCodeen, wanneer het artikel die nodig heeft,expiryDate.
Het antwoord bevat de nieuwe stand van het artikel in dat magazijn:
{ "movementId": 98231, "stockItemId": 345, "warehouseId": 1, "locationId": 77, "delta": -3,
"onHand": 42, "sellable": 40, "available": 35, "sequence": 98231, "replayed": false }
Magazijnresources
Alle lijsten gebruiken cursor en limit (1 tot 100, standaard 50) en antwoorden met items en nextCursor, nieuwste eerst. Deze resources zijn alleen uw eigen magazijngegevens: scope=partner geeft 422. Alle velden van verzoek en antwoord staan in de referentie op qrx.eu/api.
Ontvangsten:
GET /api/v1/receipts(filterstate,warehouseId,q),GET /api/v1/receipts/{id},POST /api/v1/receipts(metannounce: truewordt de ontvangst aangemeld),PATCH /api/v1/receipts/{id},POST .../{id}/lines,POST .../{id}/completeenPOST .../{id}/cancel.Inkooporders:
GET /api/v1/purchase-orders,GET /api/v1/purchase-orders/{id},POST /api/v1/purchase-orders(een concept),PATCH .../{id},POST .../{id}/lines,POST .../{id}/send,POST .../{id}/closeenPOST .../{id}/cancel. Versturen werkt precies als in PortalX: metemail: truemailt QrX de pdf naar de leverancier (of naarto), maximaal 5 keer per order en 30 keer per account per uur (429RATE_LIMIT_EXCEEDED).Voorraadartikelen en locaties:
POSTenPATCH /api/v1/stock/itemsen/api/v1/stock/locations. Locaties vereisen Full WMS met bins. De rijen vanGET itemsenGET locationshebben nuversion.Lezen:
GET /api/v1/stock/movements,GET /api/v1/picklists,GET /api/v1/counts(met/{id}en/{id}/lines),GET /api/v1/containersenGET /api/v1/tasks(met/{id}). Teamtaken zijn alleen-lezen.Een wijziging van een bestaand record vereist de
versiondie u het laatst hebt gelezen. Heeft iemand het record intussen gewijzigd, dan krijgt u 409: lees het opnieuw en probeer het nog eens.Magazijnen (scope
stock.read, Volledig WMS):GET /api/v1/warehousesmet code, naam, standaard, tijdzone, adres, contact, ontvangstinstructies, laaddocks en GLN;GET /api/v1/warehouses/{id},.../{id}/hours(ontvangst- en verzendtijden per weekdag) en.../{id}/closures(metfromencursor).Overboekingen (scope
stock.read, Volledig WMS met meerdere magazijnen en overboekingen):GET /api/v1/transfers(filterstate,warehouseId,direction) enGET /api/v1/transfers/{id}met de regels en de gegevens inshipping. Alleen lezen.Inkooporders: aanmaken en
PATCHaccepteren de kopveldenreference,supplierReference,buyerUserId,internalNote,incoterm,incotermPlace,paymentTermsDays,shippingCost,shippingVatRate,pricesIncludeVat,deliveryAddressenpartialDeliveryAllowed, en regels accepterendiscountPct,vatRate,note,confirmedQtyenconfirmedOn. Orders geven de totalen terug (netto, btw per tarief, bruto) zoals QrX ze berekent. De lijst filtert opreference,expectedFromenexpectedTo. Voorwaarden liggen vast zodra de order is verstuurd.Ontvangsten: aanmaken en
PATCHaccepterensupplierIdom een ontvangst aan een leverancier te koppelen; rijen geven het terug.Voorraadartikelen en locaties: schrijfacties op locaties accepteren
zoneofzoneIden de velden voor maat en capaciteit; schrijfacties op artikelen accepterenstorage,dangerousGoods,imageUrlenabcClassOverride.POST /api/v1/stock/adjustaccepteert uw eigen redencodes.
Idempotency-Key
Stuur per correctie een eigen unieke tekst. Herhaalt u hetzelfde verzoek met dezelfde sleutel, dan krijgt u het eerste antwoord opnieuw met
replayed: trueen wordt er niets dubbel geboekt.Dezelfde sleutel met een andere body wordt geweigerd met 409
DUPLICATE_IDEMPOTENCY_KEY.Een sleutel mag niet beginnen met een QrX-systeemprefix zoals
mcp-en mag niet eindigen op een dubbele punt gevolgd door cijfers (422).Elke POST en PATCH van de magazijnresources vereist de header
Idempotency-Key(1 tot 140 tekens). Dezelfde sleutel met dezelfde body op dezelfde route geeft het eerste antwoord opnieuw, met de headerIdempotent-Replayed: true. Een herhaalde aanmaak van een ontvangst of inkooporder geeft het record zoals het nu is.Antwoorden worden 30 dagen bewaard. Een mislukte aanroep (4xx of 5xx) wordt niet bewaard, dus u mag dezelfde sleutel opnieuw sturen.
Zolang de eerste aanroep met een sleutel nog loopt, krijgt u 409
CONCURRENCY_CONFLICTmetRetry-After. Een aanroep die halverwege is gestopt, geeft zijn sleutel na 15 minuten vrij.Een inkooporder versturen met
email: truemailt de leverancier maximaal één keer per sleutel. Mislukt een aanroep nadat de order is verstuurd maar vóór de e-mail, dan volgt er voor die sleutel geen e-mail: controleer de e-mailhistorie van de order in PortalX en verstuur opnieuw met een nieuwe sleutel.
Cursors en updatedSince
Elke lijst geeft
itemsennextCursorterug. StuurnextCursorterug alscursorvoor de volgende pagina. Null betekent het einde. Er is geen totaal.Behandel een cursor als een ondoorzichtige waarde.
Met
updatedSincekrijgt u alleen rijen die op of na dat tijdstip zijn gewijzigd. De server bekijkt maximaal 1.000 rijen per aanroep, dus een pagina kan minder rijen danlimitbevatten, zelfs geen, terwijlnextCursorgevuld is. Blijf aanroepen totdatnextCursornull is.
Voorraad bij een fulfilmentpartner: scope=partner
Bewaart een fulfilmentpartner uw voorraad, voeg dan scope=partner toe aan GET levels en GET items om uw eigen voorraad bij uw partners te lezen. Zonder krijgt u de standaard, scope=warehouse: de voorraad in uw eigen magazijnen.
Elke rij heeft
partnerCustomerId(het partnermagazijn) en uw eigen id inownerCustomerId.Gebruik
partnerCustomerIdin de query om één partner te houden, enwarehouseIdvoor één van zijn magazijnen.Locaties worden nooit teruggegeven:
locationId,GET locationsenPOST adjustantwoorden met 422 in deze scope.U hebt minstens één partner met actieve toegang nodig; op uw eigen account hoeft de magazijnvoorraad niet aan te staan.
Foutcodes
401
UNAUTHORIZED: geen geldig toegangstoken.403
STOCK_SCOPE_MISSING: de sleutel is beperkt en miststock.readofstock.write.403
ACCESS_DENIED: de magazijnvoorraad staat niet aan voor het account, of, metscope=partner, geen partner heeft actieve toegang.404
STOCK_NOT_FOUND: het artikel, het magazijn of de locatie is niet van u.400
IDEMPOTENCY_KEY_REQUIRED: een POST zonder de header.422
VALIDATION_FAILED: ongeldige invoer, bijvoorbeeld delta 0, een onbekende redencode, een ongeldige cursor, of meer dan 50 artikelen met dezelfde SKU of EAN (filter opstockItemId).409
DUPLICATE_IDEMPOTENCY_KEY: dezelfde sleutel met een andere body.409
STOCK_CONFLICT: niet genoeg voorraad, voorraad die aan een picklijst is toegewezen, een SKU die bij meerdere artikelen past, of een inactief artikel.409
CONCURRENCY_CONFLICT: stuur hetzelfde verzoek opnieuw met dezelfde sleutel.429: te veel verzoeken; wacht op
Retry-After.403
INBOUND_SCOPE_MISSING,PURCHASING_SCOPE_MISSING,FULFILMENT_SCOPE_MISSINGofTASKS_SCOPE_MISSING: de sleutel is beperkt en mist dat onderdeel.404
INBOUND_NOT_FOUND,PURCHASE_ORDER_NOT_FOUNDofNOT_FOUND: het record is niet van u.409
INBOUND_CONFLICTofPURCHASING_CONFLICT: de versie of de status staat de wijziging niet toe.429
RATE_LIMIT_EXCEEDED: te veel e-mails aan de leverancier voor een inkooporder.400
ZONE_UNKNOWN: de zone is geen actieve zone van dat magazijn. 400DG_CLASS_UNKNOWN: de klasse gevaarlijke stoffen is geen zichtbare klasse van uw account. Een reden die foto's vraagt, kan niet via de API worden gebruikt.
Wanneer neemt u contact op met ons supportteam
Neem contact op met QrX support wanneer de API ACCESS_DENIED antwoordt terwijl de magazijnvoorraad aan staat, of wanneer een stand afwijkt van PortalX. Vermeld de requestId van het antwoord, de SKU en het tijdstip. Stuur nooit de API-sleutel of het token mee.
