Stock and Warehouse Webhooks
QrX can tell your own system when stock changes, when an item runs low and when an order is picked.
It can also tell your system about warehouse documents: receipts, purchase orders, counts, containers, team tasks and more pick list and order events. See "Warehouse Document Events" below.
This article is for developers. It covers the events stock/adjusted, stock/low and fulfilment/picked. For signatures, retries and delivery logs see "Webhooks and API Keys in PortalX" and "Developer Quickstart: QrX Public API and Webhooks".
Subscribe to the Events
Go to Settings > Advanced > Webhooks and open or create a webhook.
In the event list, open the group Stock and tick
stock/adjustedandstock/low.Open the group Fulfilment and tick
fulfilment/picked.The sample payload of each event shows a full example. Use Customize payload to choose the fields that are sent.
For warehouse documents, open the groups Receipts, Purchase orders, Counts, Containers, Team tasks and Transfers and tick the events you need. The extra pick list and order events are in the group Fulfilment.
Save the webhook.
Through the API you add the same event names to eventTypes in POST /api/v1/webhooks. The stock events need QrX warehouse stock on your account, or stock that a fulfilment partner holds for you.
stock/adjusted
Sent when the stock of an item changes in a warehouse: a receipt, a pick, a shipment, a return, a count, a move or a correction. You get one event per stock item, warehouse and operation, never one per scan. A change is announced about one minute after it was booked.
{
"eventId": "stock/adjusted:1:98231",
"occurredAt": "2026-10-11T09:12:03Z",
"movementId": 98231,
"sequence": 98231,
"stockItemId": 345, "sku": "TSHIRT-M", "ean": "8712345678906",
"ownerCustomerId": null,
"partnerCustomerId": null,
"warehouseId": 1, "warehouseCode": "MAIN",
"fromLocationCode": "A-01-02", "toLocationCode": null,
"reason": "adjusted",
"documentType": "adjust", "documentId": 5521,
"movementCount": 1,
"quantity": 3,
"delta": -3,
"onHand": 42, "sellable": 40, "available": 35
}
eventId: the key to de-duplicate on. Treat it as an opaque text; do not parse it.sequence: a number that always goes up per item and warehouse. It equalslastSequenceofGET /api/v1/stock/levelsright after the movement.movementId,occurredAt: the newest stock movement in the event and its time (UTC).ownerCustomerId: the merchant the stock is held for; null for your own stock.partnerCustomerId: null, except in the owner copy described below.fromLocationCode,toLocationCode: the location the units left and entered. Null means outside stock (supplier, customer, correction) or several locations in one event.reason: for examplereceived,putaway,moved,adjusted,shipped,returned,scrapped,blocked,unblocked. Treat a value you do not know as a generic movement.documentType,documentId,movementCount: the stock document behind the change and how many movements the event sums up.quantity: units moved.delta: change of the stock on hand in this warehouse; 0 for a move, a pick or a put-away inside the warehouse.onHand,sellable,available: the level of the item in this warehouse right after the movement.
stock/low
Sent once each time an item drops to its low stock alert level or below, at the same moment as the bell notification. It is not repeated while the item stays low. See "Low Stock Alerts" for how to set an alert.
{
"eventId": "stock/low:12:4",
"occurredAt": "2026-10-11T09:13:00Z",
"ruleId": 12, "crossing": 4,
"stockItemId": 345, "sku": "TSHIRT-M", "ean": "8712345678906", "name": "T-shirt M",
"ownerCustomerId": null,
"partnerCustomerId": null,
"warehouseId": null, "warehouseCode": null,
"threshold": 10, "available": 7
}
ruleId: the alert.crossing: counts the alerts of this rule (1, 2, 3 and so on).warehouseId,warehouseCode: null when the alert counts all warehouses together.threshold: the alert level.available: the available units when the alert fired.
fulfilment/picked
Sent once per order when the phone pick is completed: the moment the picker finishes the pick list in the QrX app, every order on that pick list gets one event. A paper pick list, or one that is only worked on screen, does not send it: for those orders the first event is fulfilment/packed.
{
"eventId": "fulfilment/picked:881:120045",
"occurredAt": "2026-10-13T10:02:11Z",
"sessionId": null,
"transactionId": 120045,
"transactionKey": "TR-8F3K2M",
"orderId": "1001",
"picklistId": 881,
"pickedAt": "2026-10-13T10:02:11Z",
"pickedByUserId": "b6c0...",
"hasShorts": false
}
transactionId,transactionKey,orderId: the order, as infulfilment/packed.picklistId: the pick list. Null when a fulfilment partner picked the order for you.pickedAt: when the pick list was completed.hasShorts: true when at least one line of this order was picked short.pickedByUserId: the picker. It is off by default; switch it on with Customize payload. Null when a fulfilment partner picked.sessionId: always null for this event.
Warehouse Document Events
Every event below has an eventId (opaque, de-duplicate on it) and occurredAt. The sample payload in the editor shows every field. No event contains prices or costs.
Receipts:
receipt/created,receipt/line_received(one event per booked receipt, with the received lines) andreceipt/completed. Fields includereceiptId,receiptNumber,state,warehouseCode,purchaseOrderId,reference,supplierNameandtotals.Purchase orders:
purchase_order/created,purchase_order/sent,purchase_order/received(also when a dropship order is settled) andpurchase_order/closed(withreason). Fields includepurchaseOrderId,purchaseOrderNumber,state,supplierName,expectedOnand quantitytotals.Counts:
count/completed(the count is submitted) andcount/approved, withcountId,kind,stateandtotalssuch as counted lines and lines with a variance.Containers:
container/created,container/moved(with the previous location) andcontainer/emptied(with the target location, lines and quantity).Team tasks:
task/createdandtask/completed, withtaskId,title,status,dueAtand the object the task is about.Fulfilment:
picklist/assigned(a pick list was given to a picker),picklist/cancelled,picklist/batch_created(a batch run made several pick lists; it lists their ids) andfulfilment/snoozed(an order was snoozed, or its snooze was cleared;snoozedtells which).Transfers:
transfer/sent,transfer/received(one event per receipt at the destination, withdocumentIdand the receivedlines),transfer/completedandtransfer/cancelled. Fields includetransferId,transferNumber,state, the from and to warehouse,reference,expectedOn,sentAt,completedAt,shipping(carrier, tracking number and link, packages, weight) and quantitytotals. They belong to no sales channel.Receipt events now carry
supplierIdwhen the receipt is linked to a supplier. Purchase order events addreference,supplierReference,supplierConfirmedAtandpartialDeliveryAllowed, still without prices.
De-duplicate and Keep the Order
Every event is delivered at least once, so the same event can arrive twice. Store the
eventIdvalues you processed and skip one you have seen.Events can arrive out of order. For
stock/adjusted, store the lastsequenceper stock item and warehouse and ignore an event with a lower number.To start, or to recover after your endpoint was down, read the levels with
GET /api/v1/stock/levelsand comparelastSequence. After a long interruption, stock changes older than 6 hours are no longer announced asstock/adjusted.
Delivery Rules
A stock event belongs to no sales channel.
stock/adjustedandstock/lowgo to every active webhook of your account that ticked the event, also to a webhook that is set to one channel.fulfilment/pickedfollows the sales channel of the order, likefulfilment/packed, and needs the pack station on your account.A large burst of stock events, for example after an import or a full count, is spread over the following minutes. It never delays your order and fulfilment events.
A paused webhook skips events; they are not queued.
The events of receipts, purchase orders, counts, containers, team tasks,
fulfilment/snoozedand the inbound events belong to no sales channel either. Every active webhook of your account that ticked them receives them, also a webhook that is set to one channel, and also when the pack station is off. The receiver is the account whose warehouse document it is.The pick list events follow the sales channel of the pick list, like
picklist/created.A webhook saved less than 15 seconds ago can miss an event of that moment.
When a Fulfilment Partner Holds Your Stock
As the owner of the stock you get your own copy of the stock events for your own items, as long as the partner's access is active. The field names are the same, with these differences:
partnerCustomerIdis the partner warehouse andownerCustomerIdis your own account.fromLocationCode,toLocationCode,documentTypeanddocumentIdare always null. You never receive locations.The
eventIddiffers from the one your partner receives.stock/lowonly comes from your own low stock alerts, never from the alerts of your partner.
When to Contact Our Support Team
Contact QrX support when stock events do not arrive although the event is ticked, the webhook is active and your endpoint returns 2xx. Include the webhook name, the SKU, the warehouse and the time of the stock change.
